# D39 · OS CURSOS PRESENCIAIS COM INSCRICAO — enquadramento

**ENTREGUE:** epic **CS-94** · cards **CS-95, CS-96, CS-97** (backend) e **CS-98, CS-99, CS-100**
(frontend) · pedido **103** na fila do dono. A ordem dos seis e' a da §5.

O SETIMO dos sete blocos do CS-1 (regra 121, item 7). Texto do dono, literal e intocado:
«possibilidade de anunciar cursos presenciais na plataforma e os medicos se inscreverem».

## 1 · O que ESTE enquadramento parte, e o que ⛔ NAO parte

⛔ **A INSCRICAO ⛔ NAO ENTRA, E ⛔ NAO E' ESQUECIMENTO.** A demanda proibe-o a' letra: «O
enquadrador ⛔ NAO parte o card da inscricao sem esta resposta» — a **pergunta 94** esta' na fila do
dono (conferido: `fab estado`, item `#94 pergunta CURSOS PRESENCIAIS (demanda 39)`), e decide se a
vaga se larga e se ha' fila de espera. Sao tres tamanhos de trabalho diferentes.
⟹ **⛔ NAO se abriu pergunta nova**: a que segura isto JA' esta' lá. ⛔ Nao se gasta a fila dele
duas vezes pela mesma coisa.

O que fica FORA por causa dela, nomeado para ⛔ nao se perder:
 · o acto do MEDICO se inscrever (`POST` da inscricao);
 · o LIMITE A FECHAR a inscricao — criterio **(2)** inteiro;
 · a segunda metade do criterio **(3)** («depois de os 2 se inscreverem ⛔ nao existe presenca
   confirmada nenhuma») — porque ⛔ nao ha' quem se inscreva.
⟹ Isso e' **um card de backend + um de frontend**, e nasce quando ele responder. ⚠️ `fab enquadrar`
ⓘ INSERE cards (`fabdono.py:66-71`) e ⛔ nao os apaga: a segunda volta deste epic acrescenta-os sem
desfazer nada do que ja' estiver aprovado.

## 2 · O que foi MEDIDO, neste repo, hoje

 · `backend/prisma/schema.prisma` — **13 models**, e ⛔ NENHUM e' `Curso`, `Inscricao`,
   `Certificado` ou `Ponto`. Confirmado.
 · «curso», «inscri», «presencial» — **ZERO ocorrencias de negocio** em `backend/src`,
   `backend/prisma` e `frontend/src`: os acertos sao `cursor:` em CSS, `blocoEmCurso` no ao vivo, e
   o comentario de `vinculo.controlador.ts:47`. ⟹ O produto ⛔ NAO SABE o que e' um curso.
 · `CHAVES_PARAMETRO` tem **QUATRO** chaves na `main` (`parametro/chaves.ts:7`) — e **CINCO** em
   `epic/CS-32`, que ja' abriu `tecto_minutos_por_questao` e esta' `aprovada` a' espera de publicar.
   ⟹ Abrir outra ⛔ nao inaugura nada: e' o mecanismo que o dono escolheu (regra 53).
 · `frontend/src/app` — **19 `page.tsx`**, SETE portas e DOZE orfas em `lib/navegacao.ts`.
 · 🩸 **E HA' UMA SEGUNDA PROVA QUE A PORTA NOVA PARTE, e ⛔ nao e' so' a `navegacao.spec.ts`**:
   `frontend/e2e/alcance.spec.ts` varre o DISCO e exige, por cada rota nova, entrada em `ESPERADO`
   (alcancavel **por clique**, papel a papel), em `ANCORAS` (`:311`) e em `ESTADOS_NAO_CHEGADA`
   (`:635`) — cada uma com `ficheiro:linha`. ⟹ Esta' nos `escopo_paths` dos TRES cards de ecra, e
   nomeada no titulo, para ⛔ nenhum dev ser apanhado por ela a meio.
 · `frontend/e2e/botoes.spec.ts` conta **botao mudo em ecra de produto** em todo o `src/app`.
   ⟹ Todo o botao novo leva marca do conjunto FECHADO: `add`, `check`, `remove`, `filter_list`,
   `chevron_right` — os cinco JA' EXISTEM em `NomeDeIcone` (`Icone.tsx:28-52`) e ⛔ nao ha' peca
   nova a comprar.
 · ⛔ **⛔ NAO HA' ecra de parametros no produto**: `PUT /parametros/:chave` existe e e' SO' da
   secretaria (`parametro.controlador.ts:50-51`), e o frontend ⛔ nunca o chama. ⟹ «muda de 10 para
   25 SEM DEPLOY» exerce-se pela rota, e o que muda no ECRA e' o que o medico le'.

## 3 · Os padroes que se REUSAM, e ⛔ nao se reinventam

| o que | de onde vem, medido |
|---|---|
| `POST :id/<acto>` com **200 e ⛔ nao 201** | `vinculo.controlador.ts:47` — «⛔ nao nasce recurso nenhum, decide-se um que ja' existe» |
| a linha **⛔ nunca se apaga**, com quem assinou | `vinculo.controlador.ts:65` |
| PENDENTE le' **200 com lista vazia**, ⛔ nao 403 | `aula.controlador.ts:80-92`, `@PermitePendente` |
| SO' a secretaria escreve, os quatro leem | `nucleo.controlador.ts:45-70` |
| o **facto** guarda-se, ⛔ nao o numero | `ParticipacaoAula.minutosValidados` (schema:370) e `RespostaQuestao` **sem coluna de pontos** (schema:387) |
| a omissao do parametro vive **so' na migracao** | `migrations/20260925130000_parametro_da_secretaria/migration.sql` |
| controlador de outro modulo sob o mesmo prefixo | `questao.controlador.ts:20` — `@Controller('aulas/:aulaId/questoes')` |
| as linhas da prova semeiam-se pelo Prisma | `test/vinculo.e2e-spec.ts` (usa `PrismaService` e `ServicoIdentidade`) |

## 4 · Os territorios

**backend** (3 cards) e **frontend** (3 cards). ⛔ Sem infra: ⛔ nenhum chao novo, ⛔ nenhuma porta
nova, ⛔ nenhum banco novo. ⛔ Sem estudio: as pecas de que estes ecras precisam JA' estao no repo.

## 5 · Os seis cards

 1. **[backend] O CURSO EXISTE** — `model Curso` + migracao + `POST/GET/PATCH /cursos`.
 2. **[backend] A FOLHA DE PRESENCAS** — a linha de inscricao + confirmar UM A UM (200), depende de 1.
 3. **[backend] A CHAVE `pontos_curso_presencial`** — inteiro >= 0, omissao **so'** na migracao. Sem pai.
 4. **[frontend] A PORTA «Cursos» E A LISTA** — `/cursos`, chips de nucleo, o valor vindo do servidor. Depende de 1 e 3.
 5. **[frontend] ANUNCIAR** — `/cursos/novo`, orfa (ACTO). Depende de 4.
 6. **[frontend] CONFIRMAR, EM PAGINA** — `/cursos/[id]/presencas`, orfa (DETALHE). Depende de 2 e 5.

Os tres de ecra sao **SERIAIS de proposito**: os tres escrevem em `lib/navegacao.ts`,
`e2e/navegacao.spec.ts` e `e2e/alcance.spec.ts`. Em paralelo, seria conflito garantido em tres
ficheiros — e o dependente so' nasce depois de o pai ser **aprovado pelo QA**.

## 6 · O QUE O ENQUADRADOR DECIDIU, por ser REVERSIVEL — para o dono corrigir no aceite

 1. **TRES paginas, ⛔ nao duas.** O criterio (6) diz «as duas paginas novas»; o produto separa
    SEMPRE o ACTO da LISTA (`upas/nova`, `aulas/nova`, `nucleos/nova`). ⟹ lista · anunciar ·
    confirmar. Cada uma com os seus SEIS estados.
 2. **TODAS sob `/cursos/`**, e ⛔ nao metade em `/secretaria/cursos/`: a secretaria VE' TUDO
    (regra 112), logo a lista serve os dois papeis e ⛔ nao se duplica um ecra. Ganho medido: a
    cerca de cada card de ecra e' **uma pasta so'**.
 3. **UMA data por curso.** A regra 52 diz «as datas» (plural); o texto desta demanda diz «quando»
    e o criterio (1) diz «data». ⟹ UMA. Um fim ou uma segunda data e' **acrescento**, ⛔ nao
    refactor.
 4. **OS CAMPOS SAO CINCO** — o que e' · quando · onde · limite de vagas · nucleo. ⛔ Sem descricao
    e ⛔ sem duracao: o «etc» e' dele, e «que mais campos leva um curso?» e' pergunta ABERTA, que
    ⛔ nao se faz (regra 60). Ele ve'-os no ecra e corrige.
 5. **A porta leva `icone: undefined`** — precedente exacto de «UPAs», «Nucleos» e «Sistema». ⛔ Nao
    ha' nome de icone para cursos no conjunto fechado e ⛔ nao se inventa peca dentro de um card de
    ecra (a regra 86 proibe ICONE sozinho, ⛔ nao rotulo sozinho).
 6. **A linha de inscricao nasce SEM estado proprio** — so' com a confirmacao (`compareceu`,
    `confirmadoPorId`, `confirmadoEm`). E' o que torna a resposta a' pergunta 94 um ACRESCENTO:
    (A) ⛔ nao acrescenta nada · (B) acrescenta o largar da vaga · (C) acrescenta a fila.
 7. **CORRIGIR UMA MARCA E' PERMITIDO**, e reescreve quem assinou e quando — a linha ⛔ NUNCA se
    apaga. Uma secretaria que carregue no botao errado ⛔ nao pode ficar sem volta.
 8. **A inscricao pelo MEDICO ⛔ nao e' de nenhum destes cards** (§1). No card 2 as linhas da prova
    semeiam-se pelo Prisma, como o `vinculo.e2e-spec.ts` ja' faz.

## 7 · A chave

O rastreador deste produto e' **o livro da propria fabrica** — ⛔ ⛔ nao ha' Jira aqui (a regra 3,
`MSS-<n>`, tem ambito `produto:maissaude` e diz «⛔ nao improvise uma chave»). Precedente escrito:
`ENQUADRAMENTO-D28.md:122-125`. As chaves `CS-<n>` correm em sequencia e leem-se do `card` + da
`demanda`; o numero e' tomado **no instante da entrega**, porque ha' outros enquadradores a correr
em paralelo (medido: CS-70..CS-93 foram consumidos DURANTE esta sessao, pelas demandas 33, 34, 35 e 40 — a
primeira leitura desta sessao dava CS-70 livre, a ultima CS-94. ⟹ O numero le-se no INSTANTE da
entrega, ⛔ nao no inicio do trabalho: `escopo/ENQUADRAR-D39.py` fa'-lo e ⛔ nao ha' chave escrita
a' mao em lado nenhum.)

## 8 · OBSERVACOES — ⛔ nao sao achados, ⛔ nada disto me impediu de continuar

 1. ⚠️ **`epic/CS-32` tambem mexe em `parametro/chaves.ts`** e ja' esta' `aprovada`. Quando as duas
    integrarem, o conflito nesse ficheiro e' de UMA linha da lista. ⟹ Por isso ⛔ NENHUM aceite do
    card 3 conta chaves («⛔ nao ha' 5» / «ha' 6»): medem-se **os nomes**, e as quatro antigas.
 2. ⚠️ **`epic/CS-65` (demanda 38, protocolos) tambem acrescenta uma porta** e mexe nos mesmos tres
    ficheiros de navegacao. A resolucao e' o rebase do epic, ⛔ nao um card — mas quem especificar
    os cards 4, 5 e 6 deve ler `navegacao.ts` **no epic**, ⛔ nao na `main`, senao escreve a conta
    das portas errada.
 3. ⚠️ O criterio (6) pede «captura dos SEIS estados» — e o estado **SEM PERMISSAO** de `/cursos`
    ⛔ nao se alcanca pelo servidor real (`GET /cursos` deixa ler os quatro papeis, como
    `GET /nucleos` e `GET /aulas`). ⟹ Exerce-se como o produto ja' o exerce: **403 simulado**
    (`e2e/calendario.spec.ts:828` e `:844`, `sem-permissao-403`). Esta' escrito nos aceites.
 4. ⚠️ `fab enquadrar --help` rebenta com `ValueError` (`fabdono.py:30`: `int('--help')`) em vez de
    imprimir o uso. ⛔ Nao me travou — o uso esta' no `fab --help`. Fica aqui para quem vier.
