Skip to content

feat(squads): squad_applications + ApplyToSquad gated no APTO (#360) - #533

Open
sirelves wants to merge 1 commit into
feat/squadsfrom
story/360-squad-applications
Open

feat(squads): squad_applications + ApplyToSquad gated no APTO (#360)#533
sirelves wants to merge 1 commit into
feat/squadsfrom
story/360-squad-applications

Conversation

@sirelves

Copy link
Copy Markdown
Contributor

Materializa a candidatura a um squad, o único fluxo que o módulo conduz, gated no APTO do onboarding.

  • Migration squad_applications: status (default pending), message, decided_by, decided_at, INDEX (squad_id, status) e o partial UNIQUE (squad_id, user_id) WHERE status = 'pending'
  • Model SquadApplication (PHPDoc @property, #[Table], #[UseFactory], casts) + SquadApplicationFactory + enum ApplicationStatus (pending/approved/rejected)
  • Action ApplyToSquad: lê OnboardingCompletionGate::isCompleted($user, OnboardingType::Squads) e barra quem não é APTO com NotAptForSquads, cuja mensagem já nomeia o onboarding exigido para a UI direcionar
  • Candidatura pendente duplicada cai no índice parcial e vira ApplicationAlreadyPending

Sobre a duplicata pendente

Não tem SELECT antes do insert: duas candidaturas simultâneas leriam "nenhuma pendente" e inseririam as duas. Quem decide é o índice parcial, e a Action traduz a violação para a exception de domínio. Como candidatura recusada sai do índice, candidatar-se de novo depois continua valendo (tem teste pra isso).

Fora de escopo (por dependência)

Plano de testes

  • ApplyToSquadTest.php: APTO abre pending com mensagem, não-APTO barrado (sem onboarding, onboarding em progresso, só o Welcome concluído), duplicata pendente barrada, candidatura recusada não bloqueia nova, pendente em outro squad não bloqueia. 7/7 verdes
  • Suite de app-modules/squads: 47/47 verdes
  • make check (rector + pint + phpstan) limpo

Closes #360

Abre o único fluxo que o módulo conduz: a candidatura. Entrar exige o gate
APTO do onboarding, então quem não concluiu o onboarding Squads é barrado e
direcionado para lá.

O limite de uma candidatura pendente por squad é o índice parcial
UNIQUE (squad_id, user_id) WHERE status = 'pending', não um SELECT prévio:
duas candidaturas simultâneas leriam "nenhuma pendente" e inseririam as
duas. O insert decide. Uma candidatura recusada sai do índice, então
candidatar-se de novo depois continua valendo.

A decisão do capitão (aprovar/recusar) fica na #361, e a exclusividade de
um squad ativo por pessoa na #362.
@sirelves
sirelves requested a review from a team August 31, 2026 14:44
@stherzada stherzada added this to the Squads milestone Aug 31, 2026
@stherzada stherzada linked an issue Aug 31, 2026 that may be closed by this pull request
5 tasks
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.

feat(squads): squad_applications + ApplyToSquad (gated em APTO)

2 participants