Implementation Plan: Validação e escopo por CRP¶
Branch: 004-crp-scope-validation | Date: 2026-08-11 | Spec: spec.md
Summary¶
Evoluir o perfil profissional para CPF e CNPJ simultâneos, armazenar múltiplos registros CRP vinculados a um documento, validar CRPs em produção com carência provisória de cinco dias e aplicar um filtro opcional por CRP. A propriedade continua em ownerUserId; patients recebe a atribuição raiz de CRP e entidades clínicas derivam por paciente. Bloqueios são decisões calculadas por ação, agregando cadastro, CRP e tier. BullMQ executa tentativas futuras, mas datas persistidas no PostgreSQL determinam expiração mesmo sem worker.
Technical Context¶
Language/Version: TypeScript 5.9; Bun 1.3 API/worker; Node.js 22 web.
Primary Dependencies: Elysia 1.4, Drizzle ORM 0.45, TypeBox, BullMQ/ioredis; Next.js 15.4, React 19, TanStack Query 5, React Hook Form/Zod e shadcn/ui.
Storage: PostgreSQL com migration aditiva; Redis existente para filas.
Testing: Bun unit/integration, typecheck; Next typecheck/build; Playwright browser → API → PostgreSQL.
Target Platform: Containers Linux e navegadores modernos responsivos.
Project Type: Web + REST API + worker em deployables separados.
Performance Goals: Filtro não adiciona mais de uma consulta de escopo por request; listagens usuais p95 < 300 ms; troca visual utilizável < 2 s.
Constraints: owner sempre obrigatório; CRP é filtro redutor, nunca autorização primária; legado sem CRP visível em “Todos”; sem payload externo bruto; validação externa somente em produção; cinco pacientes free por owner.
Scale/Scope: Migration, domínio CRP/capabilities, fila/worker, pacientes e domínios derivados, perfil/onboarding, seletor global e testes verticais.
Constitution Check¶
Pre-design gate¶
| Gate | Status | Evidence |
|---|---|---|
| Specification before implementation | PASS | Spec aprovada pelo owner e checklist completo. |
| Contract-first boundaries | PASS | Contratos HTTP, provider e decisões de operação documentados antes do código. |
| Vertical slice verification | PASS | Quickstart inclui API, worker, banco e browser com dados determinísticos. |
| Clinical data safety | PASS | ownerUserId permanece obrigatório; CRP só restringe; jobs revalidam ownership. |
| Legible structure | PASS | Domínios explícitos, paciente como raiz e serviço único de capabilities. |
| Product constraints | PASS | Next/pnpm, Bun/Elysia, PostgreSQL versionado, pt-BR e shadcn preservados. |
Post-design re-check¶
PASS. A migration é expand/contract, o contrato cobre falhas e N bloqueios, e nenhuma complexidade exige exceção constitucional.
Project Structure¶
specs/004-crp-scope-validation/
├── contracts/{account-capabilities.openapi.yaml,crp-provider.md,crp-scope.openapi.yaml}
├── data-model.md
├── plan.md
├── quickstart.md
├── research.md
├── spec.md
└── tasks.md
prontuare-api/
├── drizzle/0008_crp_scope.sql
├── src/
│ ├── db/schema.ts
│ ├── domains/{profile,crp,capabilities,clinical,calendar,dashboard,forms,attendance,ai}/
│ ├── lib/{identity-scope.ts,documents.ts}
│ └── worker.ts
└── test/{crp.unit.test.ts,crp.integration.test.ts,crp-scope.integration.test.ts,capabilities.integration.test.ts}
prontuare-web/
├── app/(dashboard)/_components/
├── app/(dashboard)/settings/profile/
├── app/(dashboard)/patients/
├── components/{crp-scope-provider.tsx,operation-blockers.tsx}
├── lib/{api.ts,schemas.ts}
└── tests/crp-scope.spec.ts
Structure Decision: Preservar os deployables atuais. Perfil/CRP e capabilities são domínios próprios na API; escopo HTTP é centralizado mas serviços continuam validando owner/CRP para workers. No web, um provider controla preferência visual e o cliente HTTP injeta o header.
Delivery Design¶
- Migration aditiva e contratos.
- Perfil, registros CRP, adapter, fila e capabilities.
- Escopo de pacientes e derivação nos domínios clínicos.
- Cadastro reutilizável, seletor “Todos”/CRP e N bloqueios.
- Migração/compatibilidade, testes verticais, rollout e rollback.
Rollout and Rollback¶
- API/migration primeiro, worker depois, web por último.
- Novas contas exigem onboarding; existentes preservam acesso e pacientes
crp_id=nullem “Todos”. - Flags independentes para provider externo, enforcement de onboarding e filtro visual.
- Rollback não remove colunas/tabelas; API antiga continua operando por owner e web novo exige deploy coordenado.