Implementation Plan: Fechamento das Lacunas Pós-Migração¶
Branch: 003-post-migration-gaps | Date: 2026-08-10 | Spec: spec.md
Input: Feature specification from specs/003-post-migration-gaps/spec.md
Summary¶
Restaurar o calendário visual usando o contrato de agendamentos já existente, mover conexões OAuth para /calendar/settings e criar um resumo autenticado do dashboard. Pacientes ativos e consultas de hoje serão agregados no PostgreSQL por owner e fuso. Documentos e receita terão estado explícito unavailable porque o schema atual não possui fontes persistidas e auditáveis. CEP, CNPJ e CFP serão encerrados neste ciclo por um ADR de produto; uma decisão de adoção abrirá outra feature antes de qualquer integração.
Technical Context¶
Language/Version: TypeScript 5.9; Bun 1.3 na API; Node.js 22 no web.
Primary Dependencies: Elysia 1.4, Drizzle ORM 0.45 e TypeBox na API; Next.js 15.4, React 19, TanStack Query 5, date-fns 4, lucide-react e shadcn/ui no web.
Storage: PostgreSQL existente. Nenhuma migration é necessária para calendário ou resumo; a decisão externa é documentada em Markdown.
Testing: Bun unit/integration tests na API; TypeScript typecheck e Next.js build no web; Playwright para browser → API → PostgreSQL.
Target Platform: Navegadores modernos responsivos; containers Linux nos deploys separados de web e API.
Project Type: Aplicação web e serviço REST em repositórios isolados dentro do workspace de migração.
Performance Goals: p95 menor que 200 ms nas leituras REST de calendário e resumo com dados de validação; resultado visual utilizável em até 2 segundos; interações locais da grade sem bloqueio perceptível.
Constraints: Ownership individual obrigatório; resposta do dashboard calculada em um único referenceAt; datas persistidas como instantes e agrupadas pelo fuso IANA validado; nenhum conteúdo clínico em eventos; estados unavailable não podem virar zero; sem nova integração externa ou segredo nesta feature.
Scale/Scope: Duas rotas web, um endpoint novo, extensão do cliente tipado, componentes de calendário, testes API/E2E e um ADR de três decisões. O limite inicial de consulta do calendário é de 42 dias por requisição.
Constitution Check¶
Pre-design gate¶
| Gate | Status | Evidence |
|---|---|---|
| Specification before implementation | PASS | spec.md contém escopo, fora de escopo, erros, critérios e aguarda aprovação do owner. |
| Contract-first boundaries | PASS | O plano produz contratos separados de dashboard, calendário/UI e decisão externa antes das tarefas. |
| Vertical slice verification | PASS | quickstart.md cobre API, banco, browser, mobile e teclado com dados determinísticos. |
| Clinical data safety | PASS | Todas as consultas filtram ownerUserId; eventos não carregam conteúdo clínico; erros não revelam outro owner. |
| Legible structure | PASS | A feature reutiliza domínios existentes, não adiciona serviço/repositório e explicita métricas indisponíveis. |
| Product constraints | PASS | Next.js/pnpm, Bun/Elysia, shadcn/ui e pt-BR são preservados; sem migration ou deploy change. |
Post-design re-check¶
PASS. Os contratos cobrem sucesso, validação, autenticação, indisponibilidade e isolamento. Não há violação que exija Complexity Tracking. A implementação permanece bloqueada até aprovação do owner.
Project Structure¶
Documentation (this feature)¶
specs/003-post-migration-gaps/
├── checklists/requirements.md
├── contracts/
│ ├── calendar-ui.md
│ ├── dashboard-summary.openapi.yaml
│ └── external-lookups-decision.md
├── data-model.md
├── plan.md
├── quickstart.md
├── research.md
├── spec.md
└── tasks.md
Source Code (repository root)¶
prontuare-api/
├── src/
│ ├── domains/
│ │ ├── calendar/{calendar.routes.ts,calendar.service.ts}
│ │ └── dashboard/{dashboard.routes.ts,dashboard.service.ts}
│ └── main.ts
└── test/{calendar.integration.test.ts,dashboard.integration.test.ts}
prontuare-web/
├── app/(dashboard)/
│ ├── calendar/{page.tsx,settings/page.tsx}
│ └── page.tsx
├── components/calendar/
│ ├── calendar-grid.tsx
│ ├── calendar-toolbar.tsx
│ ├── month-view.tsx
│ ├── week-view.tsx
│ └── agenda-list.tsx
├── lib/{api.ts,calendar.ts}
└── tests/{calendar-dashboard.spec.ts,fixtures/post-migration.ts}
Structure Decision: Preservar os dois deployables. O dashboard recebe domínio próprio na API porque agrega dados de vários domínios sem transferir regras de contagem ao web. A grade fica em componentes locais no web e reutiliza /api/appointments. Integrações OAuth são movidas, não duplicadas.
Delivery Design¶
Slice 1 — Calendar visual (MVP)¶
- Endurecer o contrato de listagem com intervalo máximo, ordenação determinística e identificação segura do paciente.
- Implementar cálculo de intervalos e layout mensal/semanal sem nova biblioteca de calendário.
- Mover a página atual para
/calendar/settingse manter callbacks OAuth direcionados a ela. - Validar navegação, sobreposição, cancelamento, mobile/lista, teclado e isolamento.
Slice 2 — Dashboard summary¶
- Adicionar
GET /api/dashboard/summarycomreferenceAte timezone. - Agregar pacientes e consultas no banco; responder documentos e receita como
unavailablecom códigos estáveis. - Substituir quatro queries/valores dispersos por uma única query no web.
- Validar limites de dia/mês, falha, retry, cache e isolamento.
Slice 3 — External lookup governance¶
- Auditar o comportamento local existente e distinguir máscara/formatação de consulta externa real.
- Preencher e aprovar uma decisão por CEP, CNPJ e CFP.
- Remover promessas incorretas da UI se a decisão for aposentar/adiar; adoção abre feature independente.
Risks and Mitigations¶
| Risk | Mitigation |
|---|---|
| Contagem de “hoje” divergir por fuso/DST | Validar timezone IANA, calcular limites uma vez a partir de referenceAt e testar bordas. |
| Grade expor nome de paciente além do necessário | Contrato retorna somente identificação mínima; nenhum dado clínico. |
| Calendário mensal disparar consultas excessivas | Intervalo máximo de 42 dias e chave de cache por from, to, timezone e view. |
| Callback OAuth voltar à grade e perder feedback | Redirecionar callback para /calendar/settings e testar sucesso/cancelamento. |
| Cards indisponíveis parecerem zero | União discriminada available/unavailable; UI nunca formata valor ausente. |
| Consulta CEP/CNPJ atual ser confundida com validação confiável | ADR e UI distinguem auto-preenchimento, validação e entrada manual. |
Rollout and Rollback¶
- Entregar calendário e dashboard como mudanças independentes, sem migration.
- Antes do deploy, executar testes API, typecheck/build dos dois serviços e Playwright real.
- Rollback do web restaura a página de conexões em
/calendar; rollback da API remove somente o registro de rota do dashboard. - O endpoint novo é aditivo. O cliente web só deve depender dele depois de API compatível estar publicada.
- Nenhum código legado em
apps/será removido nesta entrega.