Skip to content

feat(squads): bounded contexts + ADRs for onboarding & squads governance#332

Draft
danielhe4rt wants to merge 12 commits into
4.xfrom
feat/onboarding-squads
Draft

feat(squads): bounded contexts + ADRs for onboarding & squads governance#332
danielhe4rt wants to merge 12 commits into
4.xfrom
feat/onboarding-squads

Conversation

@danielhe4rt

@danielhe4rt danielhe4rt commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Artefato de fluxo de tasks

O quê

Estabelece dois novos bounded contextsonboarding (camada de Entrada) e squads (Governança) — via scaffold dos módulos + documentação de domínio (CONTEXT.md + ADRs). Sem código de runtime ainda — é a fundação de design que destrava a implementação.

Resultado de uma sessão /grill-with-docs sobre o Mapa de Fluxos dos Squads (camadas Entrada + Governança; o Núcleo do jogo fica de fora por enquanto).

Decisões principais (ver ADRs)

Onboarding (Entrada)

  • ADR-0001 — Onboarding polimórfico por tipo (OnboardingType → handler(), mesmo idioma do IdentityProvider::getClient). Modelo onboarding + tabela onboarding_steps (auditoria por etapa). Cadeia de pré-requisitos entre tipos (Welcome é pré-req de Squads). "APTO" = Squads onboarding concluído.
  • ADR-0002 — Sinal de "PR aprovado" via novo evento de domínio GithubPullRequestApproved do integration-github (transporte continua centralizado; HMAC/dedup reusados). Repo de desafio via GithubRepository.purpose = challenge. Vínculo do GitHub é gate → sem reconciliação (diverge do BDD original da P.O.).

Squads (Governança)

  • ADR-0001 — Governança como record-keeping, não workflow engine. Eleição/remoção/saída/realocação rodam off-system; o módulo registra o resultado. Candidatura é o único fluxo conduzido. Autoridade = super-admins (config('he4rt.admins')) + capitão gere o próprio squad.
  • ADR-0002 — Modelo de dados: squads, squad_members (pivot com role), squad_membership_events (append-only), squad_applications. Capitão derivado do pivot (sem captain_id). Capitão único + exclusividade "1 squad ativo" garantidos no banco (partial unique) + validação na Action.

Fora de escopo (regras humanas, aplicadas off-system)

Elegibilidade "≥1 entrega", desempate pelo Head, candidatura única, mínimo de votos proporcional, "sem reeleição direta". Só o resultado é registrado — por isso o ponto aberto "definição de entrega" não bloqueia.

Arquivos

  • CONTEXT-MAP.md — registra os dois contextos + regras de dependência
  • app-modules/onboarding/ — scaffold + CONTEXT.md + 2 ADRs
  • app-modules/squads/ — scaffold + CONTEXT.md + 2 ADRs

Follow-ups (não neste PR)

  • Implementação: migrations, models (com PHPDoc), enums, Actions, Policy, listener do GithubPullRequestApproved, campo GithubRepository.purpose
  • Mover *ServiceProvider de src/Providers/src/ (guideline .ai/02-module-architecture)
  • Atualizar o documento da P.O. (cenário de reconciliação removido)

@stherzada stherzada left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avalie as considerações, e me dê um toque.

Comment thread app-modules/onboarding/docs/adr/0001-onboarding-polimorfico-por-tipo.md Outdated
Comment thread app-modules/onboarding/CONTEXT.md
Comment thread app-modules/onboarding/CONTEXT.md
Comment thread app-modules/squads/docs/adr/0001-governanca-como-registro.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No geral não entendi quais decisões ele viu de problema, necessito de mais contexto para atuar nesse review.

Comment thread app-modules/squads/CONTEXT.md
@Clintonrocha98

Copy link
Copy Markdown
Member

up!

1 similar comment
@stherzada

Copy link
Copy Markdown

up!

Co-authored-by: Sther <72408918+stherzada@users.noreply.github.com>
Signed-off-by: Daniel Reis <danielhe4rt@gmail.com>
@stherzada

Copy link
Copy Markdown

Comentário do Elves:

Tenho apenas duas observações:

  1. No squad_members com role no pivot, o papel de capitão está garantido pela partial unique constraint, o que faz sentido. Talvez valha considerar também a geração de um evento em squad_membership_events quando houver troca de capitão, para manter a trilha de auditoria consistente com o restante do modelo.
  2. O GithubPullRequestApproved, que vem do módulo de integração com o GitHub, será disparado por webhook ou por polling?

@danielhe4rt

Copy link
Copy Markdown
Contributor Author
  1. No squad_members com role no pivot, o papel de capitão está garantido pela partial unique constraint, o que faz sentido. Talvez valha considerar também a geração de um evento em squad_membership_events quando houver troca de capitão, para manter a trilha de auditoria consistente com o restante do modelo.

R: Faz sentido capturar qualquer evento de uma squad. Por mais simples que seja, é o que precisamos no momento.

  1. O GithubPullRequestApproved, que vem do módulo de integração com o GitHub, será disparado por webhook ou por polling?

R: Ambos serão o mesmo payload, no final, o meio não importa desde que tenha a Action fazendo essa fronteira entre o Transporter;

stherzada
stherzada previously approved these changes Jun 21, 2026

@stherzada stherzada left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Só não esquece de mandar o a doc lá!

Comment thread composer.json

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pendente composer update para ajustar o composer.lock

> composer install
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. It is recommended that you run `composer update` or `composer update <package name>`.
- Required package "he4rt/onboarding" is not present in the lock file.
- Required package "he4rt/squads" is not present in the lock file.
This usually happens when composer files are incorrectly merged or the composer.json file is manually edited.
Read more about correctly resolving merge conflicts https://getcomposer.org/doc/articles/resolving-merge-conflicts.md
and prefer using the "require" command over editing the composer.json file directly https://getcomposer.org/doc/03-cli.md#require-r

| `completed_at` | timestamptz? | |
| timestamps | tz | |
| UNIQUE | `(onboarding_id, step_key)` | |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pra fins de auditoria de transicionamento e checks mais rapidos, nao valeria armazenar a transição de steps com uma coluna de previously_at? traria ganho pra disciplina de transition mencionada na linha 102

ou eles foram desenhados pra serem "ever-forward" (flow nao é um grafo direcionado, apenas guarda estados)?

PR do candidato** num repo de desafio. A plataforma precisa reagir a essa aprovação.

O `integration-github` já é o **único** ponto que fala com o GitHub: `GithubWebhookController` recebe
todos os webhooks, grava no `GithubEventLog` (lake, dedup por `delivery_id`), e o `ProjectGithubEvent`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

estamos distinguindo repositório de projeto ou ambas palavras se referem à mesma coisa? um evento emitido por um repositorio deveria RepoGithubEvent ou ProjectGithubEvent como é agora?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

por que os CONTEXT.md estão em inglês e os ADRs não? pra fins de linguagem ubiqua, não deveria serem todos no mesmo idioma?

consulta interna do `integration-github`) e furaria o encapsulamento do lake. Descartado.
- **Config de repo de desafio dentro do `onboarding`** (em vez do `purpose` na allowlist): manteria o
`integration-github` sem nenhuma categoria nova, mas duplicaria o cadastro de repos e perderia o
benefício de excluir o repo de desafio da projeção de contribuições num lugar só. Trade-off aceito

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

com o purpose acoplamos a entidade do GithubRepository no dominio de onboarding. cada type nao poderia ter um repo (unique key) como repo challenge apenas apontando pro repo (1:1)*? isso ainda permitiria excluir os repos de challenge das contribuições

*1 type aponta para 1 repo de challenge

| **OnboardingFlow** | The per-type handler (a class behind the `OnboardingFlow` contract). Declares `steps()`, `prerequisites()`, `advance()`, `isComplete()`. All type-specific rules live here. | The model — the Flow is stateless behaviour; the Onboarding is the state |
| **OnboardingStep** | One auditable stage of a flow, one row in `onboarding_steps`. Carries its own `status` + `data` (jsonb) + `completed_at`. Enables pause/resume and history. | A prerequisite (another _type_ that must be complete first) |
| **Prerequisite** | Another `OnboardingType` that must be **completed** before this one can start (e.g. `Squads` requires `Welcome`). Declared by the flow, enforced on start. | A step (intra-type) — a prerequisite is inter-type |
| **APTO** | Domain shorthand for "completed the `Squads` onboarding". The condition that unlocks squad candidacy and squad creation. It is _not_ a global flag — it is `Squads` completion. | A generic "active member" — APTO is specifically squad-eligible |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APTO ta amarrado ao contexto do onboarding de Squads ou pretendemos reutilizar esse shorthand pra futuros onboarding types? se pretendemos reutilizar acho bom ja desamarrarmos os conceitos

### Modelo

- `squads` (`status`: `draft`/`active`/`inactive`/`archived`, `objective`, `slug`, tenant-scoped).
- `squad_members` (pivot): `role` (`Captain`/`SubCaptain`/`Member`/`ExMember`), `joined_at`, `left_at`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sailor (marujo) ao inves de Member se quiserem que o schema esteja bem aderido ao tema de piratas, xd

### `squads`

`name`, `slug`, `objective` (text, nullable — `draft` pode não ter), `status` (`SquadStatus`
`draft`/`active`/`inactive`/`archived`, default `draft`), timestamps.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created_by pra auxiliar a encontrar o autor do squad no futuro (utilidade)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants