Deux livrables de WP-10 manquaient, et le second n'existait nulle part. Les modèles de documents produisent attestations et courriers types en résolvant les variables du dossier. Le rendu vit dans le domaine, avec une règle qui n'est pas négociable : une variable citée sans valeur fait échouer la génération. Une attestation trouée est un document faux, pas un document incomplet — le blanc se remarque à la relecture une fois sur deux, et la pièce part signée. De même, une variable inconnue est refusée à l'enregistrement du modèle, par l'administrateur qui l'écrit, plutôt que découverte par le gestionnaire devant le salarié qui attend. Le corps reste de l'HTML rédigé par un administrateur ; ce sont les valeurs venues du dossier qui sont échappées à l'insertion. Un nom de famille importé d'un autre outil ne doit pas pouvoir ouvrir une balise. `Document.templateId` est en ON DELETE SET NULL : une pièce déjà remise ne disparaît pas parce qu'on a effacé le modèle qui l'a produite. L'écran RGPD livre le dictionnaire donnée → finalité → base légale → destinataire → durée qu'exige la matrice n° 14. Le dictionnaire vit dans le code parce qu'il décrit le schéma ; les durées viennent de RetentionPolicy parce qu'elles se paramètrent et s'auditent. Une catégorie sans durée déclarée est signalée en rouge : le plan interdit d'appliquer une durée par défaut. L'affectation des bases légales porte un avertissement explicite. C'est une qualification juridique, pas un réglage : elle doit être confirmée par le responsable de traitement avant d'être opposée à quiconque. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
52 lines
2.2 KiB
SQL
52 lines
2.2 KiB
SQL
-- ---------------------------------------------------------------------------
|
|
-- Modèles de documents — PLAN.md §4.7 et WP-10.
|
|
--
|
|
-- `templateId` sur Document est en ON DELETE SET NULL et non CASCADE : une
|
|
-- pièce déjà remise à un salarié ne doit pas disparaître parce qu'on a effacé
|
|
-- le modèle qui l'a produite. Le lien se perd, le document reste.
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
CREATE TABLE "DocumentTemplate" (
|
|
"id" TEXT NOT NULL,
|
|
"accountId" TEXT NOT NULL,
|
|
"name" TEXT NOT NULL,
|
|
"bodyHtml" TEXT NOT NULL,
|
|
"availableFields" JSONB NOT NULL,
|
|
"archivedAt" TIMESTAMP(3),
|
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
CONSTRAINT "DocumentTemplate_pkey" PRIMARY KEY ("id")
|
|
);
|
|
|
|
CREATE UNIQUE INDEX "DocumentTemplate_accountId_name_key" ON "DocumentTemplate"("accountId", "name");
|
|
|
|
CREATE INDEX "DocumentTemplate_accountId_idx" ON "DocumentTemplate"("accountId");
|
|
|
|
ALTER TABLE "DocumentTemplate" ADD CONSTRAINT "DocumentTemplate_accountId_fkey"
|
|
FOREIGN KEY ("accountId") REFERENCES "Account"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
|
|
ALTER TABLE "Document" ADD COLUMN "templateId" TEXT;
|
|
|
|
CREATE INDEX "Document_templateId_idx" ON "Document"("templateId");
|
|
|
|
ALTER TABLE "Document" ADD CONSTRAINT "Document_templateId_fkey"
|
|
FOREIGN KEY ("templateId") REFERENCES "DocumentTemplate"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- Isolation par compte — même défense en profondeur que les autres tables.
|
|
--
|
|
-- Un modèle porte le corps d'attestations et de courriers types : sa fuite
|
|
-- livrerait la raison sociale, les mentions et la forme des actes d'un autre
|
|
-- client. L'extension Prisma filtre déjà ; ces règles valent pour le cas où
|
|
-- elle serait contournée.
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
ALTER TABLE "DocumentTemplate" ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE "DocumentTemplate" FORCE ROW LEVEL SECURITY;
|
|
|
|
CREATE POLICY tenant_isolation ON "DocumentTemplate"
|
|
USING ("accountId" = planflow_current_account());
|
|
|
|
CREATE POLICY tenant_insert ON "DocumentTemplate"
|
|
FOR INSERT WITH CHECK ("accountId" = planflow_current_account());
|