prompt inicial do projeto completo

This commit is contained in:
2026-07-22 18:45:09 -03:00
parent 6fb920d333
commit b9ede753c4
12 changed files with 64 additions and 18 deletions

View File

@@ -56,7 +56,9 @@ CREATE TABLE condominiums (
name text NOT NULL,
address text NOT NULL,
timezone text NOT NULL DEFAULT 'America/Sao_Paulo',
quiet_hours int4range, -- janela de silêncio, ex.: [22,7)
-- janela de silêncio ("quiet_hours" nos demais docs); start > end cruza a meia-noite (22 → 7)
quiet_start smallint CHECK (quiet_start BETWEEN 0 AND 23),
quiet_end smallint CHECK (quiet_end BETWEEN 0 AND 23),
created_at timestamptz NOT NULL DEFAULT now(),
version integer NOT NULL DEFAULT 0
);
@@ -82,7 +84,7 @@ CREATE TABLE units (
);
```
`quiet_hours` alimenta a defesa contra "tocar em todos os apartamentos de madrugada": dentro da janela, visitas não-pré-autorizadas vão direto para a fila de operador em vez de acordar moradores.
`quiet_start`/`quiet_end` alimentam a defesa contra "tocar em todos os apartamentos de madrugada": dentro da janela, visitas não-pré-autorizadas vão direto para a fila de operador em vez de acordar moradores. Duas colunas em vez de `int4range` de propósito: a janela típica cruza a meia-noite (22 → 7), e `int4range(22, 7)` é um range inválido no Postgres. A verificação "está na janela?" vive em `shared/validation`, testada nos dois sentidos.
## 3. Pessoas e dispositivos
@@ -258,7 +260,7 @@ CREATE TABLE access_grants (
visit_id uuid NOT NULL REFERENCES visits(id),
gate_id uuid NOT NULL REFERENCES gates(id),
granted_by uuid NOT NULL REFERENCES persons(id),
pin text, -- 6 dígitos, conferência humana
pin_hash text, -- hash do PIN de 6 dígitos; o PIN em claro só existe na tela e na notificação
valid_until timestamptz NOT NULL,
used_at timestamptz,
device_result text, -- resultado do AccessControlDevice (v2)
@@ -361,6 +363,8 @@ CREATE INDEX idx_audit_entity ON audit_log (tenant_id, entity_type, entity_id, c
**Append-only.** Nenhum `UPDATE` ou `DELETE`, garantido por permissão do usuário de aplicação no banco. É a defesa jurídica em caso de autorização indevida.
**Papéis de banco separados — sem isso o revoke é decorativo.** Dono de tabela ignora `REVOKE` e RLS (salvo `FORCE`). Portanto: o Flyway conecta como `portaria` (dono do schema, roda migrations); a aplicação conecta como **`portaria_app`**, papel sem ownership, criado no init do Postgres (ver `05-INFRA-DOCKER.md` §2). Se o backend conectar como dono, nem o append-only do `audit_log` nem as policies de RLS valem nada — e nenhum teste funcional percebe.
## 9. Row Level Security — preparada, desativada
```sql