Ouvrir le compte et les préférences au paramétrage

Quatre écrans manquaient faute de spécification. Les captures du produit audité
les fournissent : identité de l'entreprise, comportement des plannings, droits
ouverts aux salariés, décompte de paie.

Les préférences sont trois blocs typés, pas un sac de clés-valeurs. Ce n'est pas
de la rigueur gratuite : `smoothOvertimeMonthly` change le calcul des heures
supplémentaires, et un JSON libre rendrait indétectable une clé mal
orthographiée — le réglage paraîtrait actif sans l'être.

Chaque formulaire déclare les clés qu'il gouverne. Une case décochée n'arrive
pas dans le FormData ; sans cette déclaration, enregistrer « Plannings »
remettrait à faux tout « Droits », un formulaire partiel effaçant ce qu'il
n'affiche pas.

Trois réglages portent un avertissement en évidence parce qu'ils déplacent des
heures et non des pixels. Le lissage mensuel des heures supplémentaires suppose
un accord d'aménagement du temps de travail : le décompte hebdomadaire est le
principe, et sans accord l'aménagement est inopposable. Les pauses rémunérées et
l'inclusion des repos dans les heures normales changent la répartition entre
heures normales et majorées. Un interrupteur qui coûte de l'argent ne doit pas
se présenter comme un réglage d'affichage.

La ligne de préférences est créée à la demande : son absence vaut « tous les
défauts ». Semer une ligne à l'installation obligerait à migrer chaque compte au
premier réglage ajouté.

L'adresse va sur le compte et non sur l'établissement : le siège porte
l'identité juridique et figure au registre du personnel, là où l'établissement
porte le SIRET, le fuseau effectif et les plannings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5 committed 2026-08-11 12:59:53 +02:00
1 parent f0ef6f12a1
commit d8060eb4a9
11 files changed
+945

No files matched your search

@@ -0,0 +1,67 @@
-- ---------------------------------------------------------------------------
-- Siège social et préférences du compte — PLAN.md §9.
--
-- Les colonnes d'adresse vont sur Account et non sur Location : le siège figure
-- sur les documents édités et au registre du personnel, et il n'est pas
-- nécessairement celui d'un magasin.
--
-- Les préférences sont une table à part plutôt que dix colonnes de plus sur
-- Account : elles changent des calculs, se relisent ensemble, et la séparation
-- garde lisible ce qui identifie l'entreprise et ce qui paramètre l'outil.
-- ---------------------------------------------------------------------------
ALTER TABLE "Account" ADD COLUMN "addressLine" TEXT;
ALTER TABLE "Account" ADD COLUMN "postalCode" TEXT;
ALTER TABLE "Account" ADD COLUMN "city" TEXT;
ALTER TABLE "Account" ADD COLUMN "country" TEXT NOT NULL DEFAULT 'FR';
ALTER TABLE "Account" ADD COLUMN "timezone" TEXT NOT NULL DEFAULT 'Europe/Paris';
CREATE TABLE "AccountPreferences" (
"accountId" TEXT NOT NULL,
"defaultMealPerShift" BOOLEAN NOT NULL DEFAULT false,
"paidBreaks" BOOLEAN NOT NULL DEFAULT false,
"lockEmployeeMeals" BOOLEAN NOT NULL DEFAULT false,
"employeesSeeOwnTotals" BOOLEAN NOT NULL DEFAULT true,
"employeesSeeTeamPlanning" BOOLEAN NOT NULL DEFAULT false,
"hideForfaitCounters" BOOLEAN NOT NULL DEFAULT true,
"eveningShiftStartMinutes" INTEGER NOT NULL DEFAULT 1200,
"employeesEditOwnProfile" BOOLEAN NOT NULL DEFAULT true,
"employeesSeeOwnTimesheets" BOOLEAN NOT NULL DEFAULT true,
"employeesSeeTeamContacts" BOOLEAN NOT NULL DEFAULT false,
"managerCreatedArePlannable" BOOLEAN NOT NULL DEFAULT false,
"directorsSharePeople" BOOLEAN NOT NULL DEFAULT false,
"directorsAccessHrDashboard" BOOLEAN NOT NULL DEFAULT true,
"directorsSeePaidLeave" BOOLEAN NOT NULL DEFAULT true,
"managersSeePaidLeave" BOOLEAN NOT NULL DEFAULT false,
"smoothOvertimeMonthly" BOOLEAN NOT NULL DEFAULT false,
"includeRestInNormalHours" BOOLEAN NOT NULL DEFAULT false,
"autoEmployeeNumber" BOOLEAN NOT NULL DEFAULT false,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "AccountPreferences_pkey" PRIMARY KEY ("accountId")
);
ALTER TABLE "AccountPreferences" ADD CONSTRAINT "AccountPreferences_accountId_fkey"
FOREIGN KEY ("accountId") REFERENCES "Account"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- ---------------------------------------------------------------------------
-- Isolation par compte.
--
-- La clé primaire *est* l'identifiant de compte, si bien qu'une fuite
-- supposerait déjà de connaître l'identifiant visé. La politique reste posée :
-- la défense en profondeur ne se dispense pas au motif que l'attaque serait
-- malcommode.
-- ---------------------------------------------------------------------------
ALTER TABLE "AccountPreferences" ENABLE ROW LEVEL SECURITY;
ALTER TABLE "AccountPreferences" FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON "AccountPreferences"
USING ("accountId" = planflow_current_account());
CREATE POLICY tenant_insert ON "AccountPreferences"
FOR INSERT WITH CHECK ("accountId" = planflow_current_account());
+71
View File
@@ -19,6 +19,14 @@ model Account {
name String
siren String?
apeCode String?
/// Siège social. Il figure sur les documents édités et au registre unique du
/// personnel ; il n'est pas déduit de l'établissement, qui peut être ailleurs.
addressLine String?
postalCode String?
city String?
country String @default("FR")
/// Fuseau du compte. Un établissement peut le surcharger (Location.timezone).
timezone String @default("Europe/Paris")
collectiveAgreementId String?
/// Surcharges d'accord d'entreprise (PLAN.md §6.3). Vide aujourd'hui :
/// l'organisation auditée n'a pas d'accord d'entreprise.
@@ -37,6 +45,69 @@ model Account {
documentTemplates DocumentTemplate[]
legalConfig LegalConfigEntry[]
installation Installation?
preferences AccountPreferences?
}
/// Préférences du compte — PLAN.md §9, réglages « préférences » et « paie ».
///
/// Trois blocs typés plutôt qu'un sac de clés-valeurs. Ce n'est pas de la
/// rigueur pour la rigueur : `smoothOvertimeMonthly` change le **calcul** des
/// heures supplémentaires, et un réglage qui change un calcul doit être lisible
/// dans le schéma, migrable, et impossible à renseigner de travers. Un JSON
/// libre rendrait indétectable une clé mal orthographiée — la préférence
/// paraîtrait active et ne le serait pas.
///
/// Une ligne par compte, créée à la demande : l'absence de ligne vaut « tous
/// les défauts », et les défauts sont ceux du modèle.
model AccountPreferences {
accountId String @id
// --- Plannings ---------------------------------------------------------
/// Compter un repas par créneau sans saisie.
defaultMealPerShift Boolean @default(false)
/// Pauses payées : elles cessent alors d'être déduites du temps de travail.
paidBreaks Boolean @default(false)
/// Interdire au salarié de modifier son repas.
lockEmployeeMeals Boolean @default(false)
/// Le salarié voit son total d'heures planifiées et réelles de la semaine.
employeesSeeOwnTotals Boolean @default(true)
/// Le salarié voit le planning des autres membres de son équipe.
employeesSeeTeamPlanning Boolean @default(false)
/// Masquer les compteurs — et les alertes — des salariés au forfait jours.
/// Un forfait jours ne se compte pas en heures : afficher un écart
/// hebdomadaire sur ces lignes produit une alerte qui n'a pas de sens.
hideForfaitCounters Boolean @default(true)
/// Heure à partir de laquelle un créneau est « du soir », en minutes depuis
/// minuit. 1200 = 20:00.
eveningShiftStartMinutes Int @default(1200)
// --- Droits ------------------------------------------------------------
employeesEditOwnProfile Boolean @default(true)
employeesSeeOwnTimesheets Boolean @default(true)
/// Annuaire ouvert : téléphone et adresse e-mail de toute l'équipe.
employeesSeeTeamContacts Boolean @default(false)
/// Un salarié créé par un manager est planifiable sans validation.
managerCreatedArePlannable Boolean @default(false)
directorsSharePeople Boolean @default(false)
directorsAccessHrDashboard Boolean @default(true)
directorsSeePaidLeave Boolean @default(true)
managersSeePaidLeave Boolean @default(false)
// --- Paie --------------------------------------------------------------
/// Décompter les heures supplémentaires au mois plutôt qu'à la semaine.
///
/// **Risque juridique.** Le décompte hebdomadaire est le principe (art.
/// L3121-28) ; lisser au mois suppose un accord d'aménagement du temps de
/// travail. Faux par défaut, et l'écran le dit.
smoothOvertimeMonthly Boolean @default(false)
/// Inclure repos et absences dans les heures normales.
includeRestInNormalHours Boolean @default(false)
/// Générer le matricule à la création plutôt que de le saisir.
autoEmployeeNumber Boolean @default(false)
updatedAt DateTime @updatedAt
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
}
/// Marqueur d'installation de l'instance — une ligne, jamais deux.