Commit Graph
26 Commits
Author SHA1 Message Date
Claude 2c0e9e8dd4 Wire authentication into the application
Adds the sign-in screen, sign-out, and a server-side guard on every
application route. The guard lives in the layout rather than the proxy
because the proxy cannot query the database to check whether a session
was revoked — and revocation is the reason sessions are stored there.

Sign-in returns one message for an unknown account and for a wrong
password, and verifies a dummy hash when the account does not exist, so
neither the wording nor the timing enumerates staff addresses. An
end-to-end test compares the two messages rather than trusting the
code to keep them aligned.

The shell now shows the signed-in person and their role from the
database instead of hardcoded initials.

Playwright signs in once in a setup project and shares the cookie;
argon2 is deliberately slow, and logging in per test would also drive
the shared failed-attempt counter toward a lockout. The seed resets
that counter so repeated local runs cannot lock the demo account.

Two test locators had to be scoped to the form: Next's route announcer
carries role="alert" and an empty string, which silently satisfied the
assertion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 22:45:24 +00:00
Claude 11763142d5 WP-01: tenancy, identity and capability authorization
Adds the data model for accounts, locations, teams, users, memberships
and scopes, plus roles, the 70-capability catalogue, database-backed
sessions, and the audit log.

Isolation is enforced twice, independently. A Prisma extension injects
accountId into every query, and PostgreSQL row-level security filters
underneath it, keyed on a transaction-local setting. The first alone
leaves raw queries unguarded; the second alone returns empty results
without saying why.

Integration tests prove both against a real database rather than
through the application layer, which would only prove the application
layer. They create a restricted role to do it — and that exposed a trap
worth naming: **a PostgreSQL superuser bypasses row-level security even
with FORCE**. Connecting the app as one silently disables the second
layer while every application test still passes. checkTenantIsolation
now refuses to start in production on such a database, warns in
development, and reports through /api/sante. The README explains the
role to create.

The audit log is append-only by trigger, so it resists even a
superuser: a trail that can be rewritten proves nothing. Entries
carrying an adjustment or an unlock are rejected without a
justification, and known secret-bearing fields are redacted before
writing — the log is read, exported and kept for years, so it must not
become a second unencrypted copy of what is encrypted elsewhere.

Sensitive columns use AES-256-GCM with the key held outside the
database. Sign-in verifies a dummy hash for unknown accounts so timing
does not enumerate addresses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 22:39:33 +00:00
Claude 93852c2602 Fix four defects the screenshots and tests exposed
Verifying the rendered pages rather than the build turned up real bugs:

- The WP-00 health page still sat at src/app/page.tsx and silently won
  the route over the new Aperçu screen, so the home page was a database
  status readout. Moved to /api/sante, where a probe belongs, and wired
  into the compose healthcheck.
- The unassigned row showed a +14 h delta against a contract of zero,
  reading as an overshoot when it is simply the volume left to staff.
  It now shows what there is to fill.
- Two sidebar entries lit at once: an anchor link matched its own page,
  and /equipe matched an employee record. Highlighting now resolves to
  the most specific match, and a test asserts exactly one entry lights
  per screen.
- Section tabs with no built screen pointed at the home page, which
  reads as a broken tab. They now lead to their first entry's
  placeholder.

Also gives truncated compliance alerts a title attribute, so a narrow
cell no longer says there is a problem without saying which.

Playwright can reuse a preinstalled browser through
PLAYWRIGHT_CHROMIUM_PATH when its revision differs from the bundled one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 22:26:38 +00:00
Claude 4012f32f7f Complete the six application screens
Adds the day timeline, team list, employee record and leave calendar.
The design export shipped data for these but no markup, so their layout
is designed here from the data shapes and the established style; only
Aperçu and the week grid are ports.

The day view carries a per-hour headcount band. Where the week view
answers "who works how much", this one answers "who is on the floor at
14:00", and the band makes coverage gaps visible without reading every
lane.

Two fixes the tests and linter caught:

- The poste derivation variables were missing from globals.css. Hues
  and tiers were ported but not the --post-*-bg/fg/edge that consume
  them, so every shift chip would have rendered colourless. The palette
  test now asserts all 36 exist.
- ThemeToggle synced state in an effect. The document's data-theme
  attribute is the real store — it is set by the inline script before
  React exists — so it now subscribes with useSyncExternalStore instead
  of keeping a copy that is wrong on first render.

Counter tests cover the DST cases in both directions: a 22:00–06:00
shift lasts 7 or 9 hours on the changeover nights, never 8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 22:16:52 +00:00
Claude a24c1b821c Add the application shell, Aperçu and the week grid
Ports the shell and Aperçu screen from the Claude Design export, and
builds the week grid from the design system's grid specification.

The theme is applied by a nonced inline script before first paint.
Without it the page renders light and then swaps, which is a white
flash for anyone working in dark. The nonce our CSP already emits is
what makes an inline script possible at all.

Demo data lives in src/lib/demo behind a README stating it is fictional
and replaceable. Screens import from there and nowhere else, so the
directory can be deleted wholesale once real queries land.

Weekend columns are shaded because in retail those are the days that
carry counterparts — mayor-authorised Sundays and their compensatory
rest — and scheduling one by accident is the failure worth preventing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 22:12:23 +00:00
Claude 8c0cfd3b0c Port the design tokens and the planning primitives
Brings in the token set from the Claude Design export: warm neutrals,
semantic status colours, and the twelve-hue categorical poste palette,
in light and dark. Declared through Tailwind's @theme so utilities
compile to var(--color-*) and follow the theme without per-component
branching.

The poste palette derives every hue from one formula with an
alternating lightness step, so neighbouring hues never land at the same
lightness. ShiftChip always prints the poste code alongside the fill:
colour carries meaning in the grid, and a grid has to stay readable in
print, in greyscale, and to someone who confuses red and green.

Week counters live in src/domain/counters rather than in the component,
because the same numbers will feed the hours report and the payroll
export later. Durations are whole minutes: decimal hours drift by a
minute in ways that are invisible on screen and wrong on a payslip.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 22:08:08 +00:00
Claude 41ac2fa0af Add the design brief for Claude Design
DesignSync cannot authorize from this environment, so the brief is
versioned here for the user to paste into claude.ai/design.

Records two constraints the design must respect or its output cannot
ship: no external resources, since the CSP names no third-party origin
and a test fails if that changes — which rules out Google Fonts — and
a categorical palette that survives colour-blindness, since shift
colour carries meaning in the planning grid rather than decorating it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 17:55:27 +00:00
Claude dd639a86f5 WP-00: application foundation
Scaffolds the project: Next.js 16 App Router with strict TypeScript,
Prisma 7 on PostgreSQL 16, Tailwind 4, Vitest, Playwright, CI, and a
standalone Docker image that applies migrations on boot.

Makes the no-tracker rule of PLAN.md 3.7 enforceable rather than
stated. A per-request nonce-based CSP names no external origin, a unit
test fails if any network directive gains one, and a second test fails
if a tracking package appears in package.json. The end-to-end test
drives the standalone server the Docker image runs, not `next dev`,
so a proxy matcher that stopped matching could not pass unnoticed.

Environment is validated at import, so a missing DATABASE_URL fails at
boot with a readable message instead of surfacing later as a driver
error mid-export. ENCRYPTION_KEY is checked to be 32 bytes.

Three deviations from the plan, recorded in PLAN.md and README:
Next 16 rather than 15, `proxy.ts` rather than the now-deprecated
`middleware.ts`, and database-backed sessions rather than Auth.js v5,
which is still beta and whose JWTs would make the session revocation
required by compliance item 23 awkward.

Verified locally against PostgreSQL 16: migrations apply, extensions
created, typecheck, lint, 9 unit tests and the end-to-end header test
all pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 17:54:11 +00:00
LogiFlow 21c98f3b47 Merge pull request #6 — forfait jours et base légale du dimanche
Forfait jours et correction de la base légale du dimanche
2026-08-07 19:30:35 +02:00
Claude 4c0f6e9b95 Add forfait jours and correct the Sunday rule's legal basis
The employer confirmed three things: some managers are on forfait
jours, the working week is 35h, and there is no company-level
agreement. The third one invalidates an earlier claim in the plan.

Sunday: the spec attributed the 100% rate to a company agreement.
With no such agreement, and the branch setting no Sunday rate, the
basis is article L3132-27 on mayor-authorised Sundays. That article
requires pay at least doubled AND compensatory rest of equal
duration, and caps the year at twelve such Sundays. The plan only
carried the pay side, so working a Sunday would have silently
skipped a distinct entitlement. Adds SUNDAY_MAYOR_QUOTA and writes
the rest to the ledger. Which Sunday regime the stores operate
under still needs confirming, since the compensation differs.

Forfait jours: brought into scope. IDCC 1517 is the enabling
agreement, so no company agreement is needed. Contracts carry
workTimeArrangement, the 218-day cap, and the individual written
agreement without which activation is refused. Such contracts leave
the hourly rules but stay under the rest rules, and gain their own
workload-review obligations. Adds ForfaitDayEntry, WorkloadReview
and a three-year retention line.

Records that no rule in scope now rests on a company norm: no
derogation to 12h days, no 46h average, no in-house annualisation.

Refreshes the matrix to the version carrying the explicit minors
stop signal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 17:30:10 +00:00
LogiFlow 87d952543e Merge pull request #5 — intégrer la matrice de conformité RH
Intégrer la matrice de conformité RH française
2026-08-07 19:16:36 +02:00
Claude 0bcdf417d1 Integrate the French HR compliance matrix
Adds matrice-conformite-rh-france-2026.md to the repo and rewrites
section 12 around it. Also fixes the link in Audit Combo/INDEX.md,
which pointed one level above the repo root.

The matrix changes the design in four places:

- Time has three states, not two. Planned, actual and paid must be
  distinguishable, and payment may never be made conditional on a
  manager's validation, nor may an authorisation workflow delete
  hours actually worked.
- The rule engine must be effective-dated, not merely versioned: a
  prior payroll has to replay identically after a rule change.
- Retention is per object with a documented start point and
  justification, explicitly not "5 years everywhere". Adds
  RetentionPolicy and the duration table.
- Control features need a server-side gate that stays closed until
  the employee notice and the CSE opinion are recorded. FeatureFlag
  carries those fields.

Adds paid-leave accrual, the 15-month carry-over, and the
obligation to inform an employee of their rights within a month of
returning from sick leave.

Scopes out payslips, DSN and geolocation, and flags on-call duty and
forfait jours as open questions. Notes that the matrix covers adult
employees only, so the MINOR_* rules remain unsourced and are now a
stop signal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 17:16:06 +00:00
LogiFlow df0a7a782e Merge pull request #4 — retirer la note obsolète sur le doublon
Retirer la note obsolète sur le doublon de l'audit des menus
2026-08-07 19:09:41 +02:00
Claude 7f2ac627f8 Drop the stale note about the duplicated dropdown audit
The root dropdowns/ tree was deduplicated in 52ac285, so the header
note telling the reader to remove it no longer describes the repo.
Only Audit Combo/dropdowns/ remains, which is what the plan already
references throughout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 17:09:26 +00:00
LogiFlow 750799ef70 Merge pull request #3 — paramètres de la convention IDCC 1517
Renseigner les paramètres de la convention IDCC 1517
2026-08-07 19:08:47 +02:00
Claude 5877efb0f2 Populate the IDCC 1517 rule parameters
Replaces the blanket stop signal in section 6.3 with the actual
parameter set, each value tagged with its origin: ordre public,
collective agreement, or company-level agreement.

Covers daily/weekly maxima (10h, 48h, 44h averaged over 12 weeks),
rest periods, the 10-consecutive-day limit, part-time minima
(24h, with the 21h and 6h derogations), complementary-hour rates
(+10%/+25%), overtime brackets (+25% to the 43rd hour, +50%
beyond), the 180-hour contingent and its rest counterpart,
modulation caps, night-work window, and the public-holiday rules
the "JF 50%" label refers to.

Key correction: the "Dimanche 100%" in the account configuration is
NOT a convention rule. IDCC 1517 sets no Sunday rate and defers to
company agreement, so SUNDAY_WORK reads an account-level override
rather than the agreement parameters, and Account gains
agreementOverrides for it.

The values come from secondary public sources, not the consolidated
Legifrance text, so a narrower validation requirement remains:
cross-check on Legifrance, obtain the company agreement, confirm
with the Silae payroll manager.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 17:05:51 +00:00
MichaelandClaude Opus 5 52ac285b94 Deduplicate the dropdown audit into a single tree
The root dropdowns/ copy held 21 screenshots that were missing from
Audit Combo/dropdowns/, so the two trees were not the exact duplicate
PLAN.md assumed. Move those screenshots under Audit Combo/dropdowns/
and drop the root copy, leaving one source of truth as the plan
prescribes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 17:06:00 +02:00
LogiFlow 82f5cc96f3 Merge pull request #2 — corriger la spécification depuis l'audit des menus
Corriger la spécification à partir de l'audit des menus déroulants
2026-08-07 17:00:33 +02:00
Claude 334da9bc59 Fix inconsistencies left by the dropdown-audit corrections
The targeted edits in the previous commit left the document
self-contradictory in places. This reconciles it.

- The stale-export rule contradicted the append-only invariant on
  PayrollExport. Staleness is now derived from
  PayPeriod.unlockedAt rather than written as a flag, and the
  period gains unlockedAt/unlockedBy to support it.
- Invariant count was still seven after an eighth was added.
- Lot references were a mix of the old Lot 0-4 numbering and the
  current WP-xx packages; all now use WP-xx.
- Articles/conversations were said to be deferred to "lot 5" while
  HR analytics were wrongly listed as deferred too.
- Section 1 now carries all five audit findings, including the
  non-terminal pay-period lock and the closed enumerations.

Adds the matching tests: the unlock/re-export cycle, cross-view
consistency, mutation refusal while locked, and CSP enforcement.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 14:56:51 +00:00
Claude f74acaf000 Correct the spec against the dropdown audit
The dropdown audit enumerates values the earlier spec had guessed.
Replaces the guesses with the observed lists and adds what they imply.

- Roles: five, not the six invented ones (owner, admin, director,
  manager, employee).
- Contract types: nine observed values, including the two dirigeant
  types that were missing; professionnalisation was never observed and
  is dropped.
- Planning has five views, not three: month and presence/absence were
  missing. All five read one model.
- Pay periods can be unlocked, and deleted while locked. Locking is
  therefore not terminal: re-locking recomputes snapshots, so exports
  from a since-unlocked period must be flagged stale or a file sent to
  Silae silently stops matching the data.
- Absence types carry a social-security flag; incomplete-profile
  filtering needs separate RUP and DPAE required-field sets.
- Document templates resolve variables per location.

Adds a telemetry invariant: the audit intercepted 2102 third-party
tracking requests and no business calls. An HR app must not leak
employee-context navigation to ad networks, so trackers are banned and
a restrictive CSP ships in WP-00 to make that testable.

Notes that the root dropdowns/ directory duplicates the copy under
Audit Combo/ byte for byte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 14:51:07 +00:00
LogiFlow 6d8897f987 Add files via upload 2026-08-07 16:45:54 +02:00
LogiFlow 2bcc195d3d Add files via upload 2026-08-07 16:42:54 +02:00
LogiFlow 1efe8d80c9 Merge pull request #1 from R0m1k3/claude/combohr-app-recreation-plan-yu7wre
Claude/combohr app recreation plan yu7wre
2026-08-07 16:39:22 +02:00
Claude d45d623259 Turn the plan into an executable build specification
Rewrites PLAN.md as a normative spec an orchestrator can build from
end to end, rather than a proposal.

Scope locked per owner decision: multi-location, Silae as the
downstream payroll system, no time clock. Timeclock entities are
dropped; actual hours are now manager-entered on the shift, with
planned hours authoritative when absent.

Adds the full Prisma schema, the permission catalogue, 17 compliance
rule codes, the leave ledger contract, the Silae CSV format
(UTF-8, semicolon, HS-/AB-/EV- prefixes), the route inventory, and
12 work packages with testable acceptance criteria.

Collective-agreement values and Silae rubric codes are declared stop
signals: the spec forbids inventing them and requires human input
before production.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 13:38:10 +00:00
Claude eed8a982c0 Add PlanFlow reimplementation plan grounded in the Combo audit
Rewrites the plan against the audit bundle rather than public docs.
Three findings changed the design:

- The audited account runs IDCC 1517 (commerces de detail non
  alimentaires), not HCR. The rules engine seeds from that agreement.
- Authorization is capability-based with separate scopes, and roles are
  customer-configurable, so Role/Permission/Scope are split from day one.
- Leave counters are a ledger of operations, not a stored balance.

Scope, stack and deployment are stated as assumptions pending
confirmation. Payroll stays export-only; DSN, eIDAS signature and DPAE
transmission are delegated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
2026-08-07 13:28:54 +00:00
MichaelandClaude Opus 5 98c0c06107 Add Combo functional audit bundle
Screenshots, contact sheets, inventory and page-by-page audit notes
for the Combo HR platform, used as the reference for the PlanFlow
reimplementation. Personal data in the captures is blurred.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:23:03 +02:00