Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project overview

SinalACS is a platform that prioritizes Primary Health Care visits in Brazil by turning structured clinical signals into a risk-ranked work queue for the Community Health Agent (ACS). Project documentation, code comments, and UI copy are in Portuguese — match that language for anything user-facing or spec-related. Current state: functional prototype, validated locally via Docker Compose; not production-ready. Already delivered: ACS institutional login (RF07, matrícula + senha/Argon2id, credentials kept locally — no integration with a real identity provider), patient passwordless login (RF01, CPF + birth date + OTP), RBAC per micro-area (RNF06), TLS 1.3 on the RPC via Traefik (RNF04), on the Traefik → backend hop (one-way TLS 1.3 with the chain verified; no mTLS, Serverpod cannot request a client certificate — #78) and on the broker (TLS 1.3 only, password + ACL + client certificate on the local stack, `scripts/qa/mtls_invariants.sh` and `scripts/qa/tls_invariants.sh`), TOTP MFA for the ACS login, RF08 micro-area persisted in the encrypted local database (72 h, per owner), the ACS refresh token (rotating, idle window 2 h, absolute cap 8 h from the password+TOTP login, family revoked on reuse/other device/inactive account; the app keeps no password) bound to the Keystore: an AES-256-GCM + RSA-OAEP envelope whose RSA key requires user authentication on every use, so the token is decrypted only through `BiometricPrompt` + `CryptoObject` on cold start (API 30+ also accepts the device PIN; on API 30+ a newly enrolled fingerprint does **not** invalidate the key; proved on the API 36 emulator only, `scripts/qa/acs_keystore_bound_e2e.sh`), plus the 30 s background lock, which stays an interface gate over the token held in RAM and "Sair e encerrar o turno", `FLAG_SECURE` on the ACS window in every build (only a debug build made with `./scripts/dev/run_acs.sh --build --captura` opens it, by a compile-time constant that release refuses), release builds that refuse the debug key unless explicitly allowed (a release keystore is still to be provisioned), the UBS call button, the per-owner offline visit queue (schema v7, legacy rows quarantined and uploaded with unknown authorship, deferred upload token, wipe only when everything is sent) and the closing of the `login()` race (`BackendClient._exclusive`), plus the backoffice account management (#43: listing, ACS create/link/activate/deactivate and password/MFA reset, staff MFA reset with the activation code emitted by the screen, and the coordinator's audit scoped to his UBS — every operation audited, refusals included). Still missing: invalidation of the token key by a newly enrolled fingerprint on API 30+ and a proof of the Keystore binding on API 24–29 (the SQLCipher key and the deferred upload token stay unbound by design), a refresh token for the patient (OTP stays 1 h), iOS, a physical-device proof on Android ≤ 8.1 (API 24–27) (the emulator on API 24 and 27 showed no theme breakage; see `PROGRESS.md`, section Tema em API 24–27), background (OS-level) upload of visits left on the device (WorkManager is outside `spec/stack.md`), a supervisor-forced device wipe (no supervisor login exists), unblocking of a queue whose 7-day upload token expired or was refused (it needs the owner to log in again and blocks the wipe) and LGPD purge of an owner who never returns (see `PROGRESS.md`, section Fila de visitas por dono e corrida do login), per-device client-certificate provisioning in production (mTLS is delivered only on the local stack), creating coordinator accounts and assigning their `ubsId` through the UI (a coordinator still exists only in the seeds and by SQL; #43 covers the ACS lifecycle and the MFA resets), the ACS's own password change (a lost password is reset by the coordination), the audit trail's append-only enforcement in the database (the chain detects tampering, it does not prevent it; no trigger/`REVOKE`), a real file download of the CSV export (it goes through the clipboard), the owner's acceptance of the green "Cadeia íntegra" exception to `spec/ui_design.md` and the data-protection officer's review of the export (`PROGRESS.md`, section #45), and a production deploy (`backend/DEPLOY.md` is only a free-tier demo path). The data-subject request handling (#42) is delivered; the validation of its anonymization rules with the data-protection officer is still open (`PROGRESS.md`).
SinalACS is a platform that prioritizes Primary Health Care visits in Brazil by turning structured clinical signals into a risk-ranked work queue for the Community Health Agent (ACS). Project documentation, code comments, and UI copy are in Portuguese — match that language for anything user-facing or spec-related. Current state: functional prototype, validated locally via Docker Compose; not production-ready. Already delivered: ACS institutional login (RF07, matrícula + senha/Argon2id, credentials kept locally — no integration with a real identity provider), patient passwordless login (RF01, CPF + birth date + OTP), RBAC per micro-area (RNF06), TLS 1.3 on the RPC via Traefik (RNF04), on the Traefik → backend hop (one-way TLS 1.3 with the chain verified; no mTLS, Serverpod cannot request a client certificate — #78) and on the broker (TLS 1.3 only, password + ACL + client certificate on the local stack, `scripts/qa/mtls_invariants.sh` and `scripts/qa/tls_invariants.sh`), TOTP MFA for the ACS login, RF08 micro-area persisted in the encrypted local database (72 h, per owner), the ACS refresh token (rotating, idle window 2 h, absolute cap 8 h from the password+TOTP login, family revoked on reuse/other device/inactive account; the app keeps no password) bound to the Keystore: an AES-256-GCM + RSA-OAEP envelope whose RSA key requires user authentication on every use, so the token is decrypted only through `BiometricPrompt` + `CryptoObject` on cold start (API 30+ also accepts the device PIN; on API 30+ a newly enrolled fingerprint does **not** invalidate the key; proved on the API 36 emulator only, `scripts/qa/acs_keystore_bound_e2e.sh`), plus the 30 s background lock, which stays an interface gate over the token held in RAM and "Sair e encerrar o turno", `FLAG_SECURE` on the ACS window in every build (only a debug build made with `./scripts/dev/run_acs.sh --build --captura` opens it, by a compile-time constant that release refuses), release builds that refuse the debug key unless explicitly allowed (a release keystore is still to be provisioned), the UBS call button, the per-owner offline visit queue (schema v7, legacy rows quarantined and uploaded with unknown authorship, deferred upload token, wipe only when everything is sent) the closing of the `login()` race (`BackendClient._exclusive`), the ACS's resolution of a visit sync conflict (#79: persisted conflict with the server copy, side-by-side screen, keep mine / edit and send / keep the server's, `visits.resolveConflict`), plus the backoffice account management (#43: listing, ACS create/link/activate/deactivate and password/MFA reset, staff MFA reset with the activation code emitted by the screen, and the coordinator's audit scoped to his UBS — every operation audited, refusals included). Still missing: invalidation of the token key by a newly enrolled fingerprint on API 30+ and a proof of the Keystore binding on API 24–29 (the SQLCipher key and the deferred upload token stay unbound by design), a refresh token for the patient (OTP stays 1 h), iOS, a physical-device proof on Android ≤ 8.1 (API 24–27) (the emulator on API 24 and 27 showed no theme breakage; see `PROGRESS.md`, section Tema em API 24–27), background (OS-level) upload of visits left on the device (WorkManager is outside `spec/stack.md`), a supervisor-forced device wipe (no supervisor login exists), unblocking of a queue whose 7-day upload token expired or was refused (it needs the owner to log in again and blocks the wipe) and LGPD purge of an owner who never returns (see `PROGRESS.md`, section Fila de visitas por dono e corrida do login), per-device client-certificate provisioning in production (mTLS is delivered only on the local stack), creating coordinator accounts and assigning their `ubsId` through the UI (a coordinator still exists only in the seeds and by SQL; #43 covers the ACS lifecycle and the MFA resets), the ACS's own password change (a lost password is reset by the coordination), the audit trail's append-only enforcement in the database (the chain detects tampering, it does not prevent it; no trigger/`REVOKE`), a real file download of the CSV export (it goes through the clipboard), the owner's acceptance of the green "Cadeia íntegra" exception to `spec/ui_design.md` and the data-protection officer's review of the export (`PROGRESS.md`, section #45), and a production deploy (`backend/DEPLOY.md` is only a free-tier demo path). The data-subject request handling (#42) is delivered; the validation of its anonymization rules with the data-protection officer is still open (`PROGRESS.md`).

Two core flows:
- **Paciente (patient)**: passwordless auth (OTP), urgency alert, structured triage, request status tracking, "Meus Dados" (LGPD).
- **ACS**: dynamic prioritization, territorialization (micro-area), offline visit registration, micro-area follow-up.

A third app, `apps/admin`, is the backoffice (Indicadores, Microáreas, Alertas, Auditoria, Pedidos do titular), reading real data from the backend since #40/#41, managing accounts since #43 (ACS create/link/activate/deactivate, password and MFA reset, staff MFA reset, audit scoped to the coordinator's UBS) and handling LGPD data-subject requests since #42 (a coordinator/admin starts review, completes or rejects them). Since #44 the Alertas and Indicadores screens refresh by a 30 s polling pulse and a coordinator/admin can escalate a red alert unacknowledged past `RED_ALERT_ESCALATION_SECONDS` (default 300 s; the alert stays `pending`, the ACS gets a reinforcement; the emulator e2e passed end to end on 2026-10-12). Since #45 the Auditoria screen filters and pages the trail, shows a per-row seal and a global chain verification computed by the server (with a tail checkpoint), and the admin (not the coordinator) can export a nine-column CSV with the export itself recorded in the same transaction; the emulator e2e, including a deliberate tampering detected on screen and by `audit_chain_check`, passed on 2026-10-13/14. Since #46 the backoffice has an Avisos tab (schedule, cancel and history of community notices; a coordinator only for his UBS) and, for the admin only, a Termos sub-tab (draft, legal review, publication of terms versions; publication is blocked until the legal review is recorded and requires an effective date at least 15 days ahead). Proved: backend unit/integration tests, widget tests, a hermetic emulator test of the tab, and a push e2e in which a scheduled notice reaches the emulator through Gorush and FCM; the legal review of the real terms text and the manual switch of the in-force version remain outside the code (`PROGRESS.md`, section #46).

Main RPC endpoints (`backend/sinalacs_server/lib/src/endpoints/`): `auth` (`loginInstitutional`, `requestOtp`, `verifyOtp`, `developmentLogin` — the last only with `ENABLE_DEV_LOGIN`), `onboarding`, `triage.evaluate`, `alerts` (`createRedAlert`, `acknowledge`, `resolve`, `statusFor`), `patients` (`listMicroArea`, `myData`, chronic conditions, `updateConsent`, `requestDataDeletion`, `requestDataCorrection`), `visits` (`sync` e `pull` com a sessão do ACS; `syncLegacy`, que usa a sessão só como transporte das visitas legadas sem dono; `syncDeferred` e `revokeUploadToken`, autenticados pelo token de envio diferido do dono, não pelo JWT), `admin` (`indicators`, `microAreas`, `alerts` e `auditLogs` — leitura do backoffice escopada por papel/UBS desde #40; desde a #43 a gestão de contas: `acs`/`staff`, `createAcs`, `setAcsMicroArea`, `setAcsActive`, `resetAcsPassword`, `resetAcsMfa` e `resetStaffMfa`; desde a #44 `escalateAlert`, `alertsPulse` e `endMonitoringSession`; desde a #46 `scheduleNotice`, `cancelScheduledNotice`, `noticeHistory`, `termsVersions`, `draftTermsVersion`, `markTermsReviewed` e `publishTermsVersion` — detalhe em `backend/CLAUDE.md`), `health.check`.
Main RPC endpoints (`backend/sinalacs_server/lib/src/endpoints/`): `auth` (`loginInstitutional`, `requestOtp`, `verifyOtp`, `developmentLogin` — the last only with `ENABLE_DEV_LOGIN`), `onboarding`, `triage.evaluate`, `alerts` (`createRedAlert`, `acknowledge`, `resolve`, `statusFor`), `patients` (`listMicroArea`, `myData`, chronic conditions, `updateConsent`, `requestDataDeletion`, `requestDataCorrection`), `visits` (`sync`, `pull` e `resolveConflict` (#79) com a sessão do ACS; `syncLegacy`, que usa a sessão só como transporte das visitas legadas sem dono; `syncDeferred` e `revokeUploadToken`, autenticados pelo token de envio diferido do dono, não pelo JWT), `admin` (`indicators`, `microAreas`, `alerts` e `auditLogs` — leitura do backoffice escopada por papel/UBS desde #40; desde a #43 a gestão de contas: `acs`/`staff`, `createAcs`, `setAcsMicroArea`, `setAcsActive`, `resetAcsPassword`, `resetAcsMfa` e `resetStaffMfa`; desde a #44 `escalateAlert`, `alertsPulse` e `endMonitoringSession`; desde a #46 `scheduleNotice`, `cancelScheduledNotice`, `noticeHistory`, `termsVersions`, `draftTermsVersion`, `markTermsReviewed` e `publishTermsVersion` — detalhe em `backend/CLAUDE.md`), `health.check`.

`PROGRESS.md` holds milestone status and the open items with owners. `spec/validation_report.md` is stale in both directions (items it lists as open are closed, and its test counts are far below the real ones) — verify against the code before trusting it.

Expand Down
Loading
Loading