Commit Graph

1028 Commits

Author SHA1 Message Date
86d949294f chore(work): finish 05-core-consent-react 2026-05-19 21:21:28 +02:00
9b6deac954 feat(core-consent): add ConsentProvider + useConsent() React subpath
Adds the ./react subpath to @repo/core-consent following the same
pattern as @repo/core-analytics/react:

- ConsentProvider wraps IConsent in React context
- useConsent() returns the injected IConsent or throws ConsentContextError
- RTL tests cover context propagation, grant/withdraw delegation,
  isGranted state reflection, getCategories, and missing-provider error
- package.json: ./react export + React optional peerDep + RTL devDeps
- tsconfig: extend react-library.json, include .tsx
- vitest.config: jsdom environment for .test.tsx + jsdom setup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 19:19:47 +00:00
33e3c093ad chore(work): finish 04-core-consent-implementation 2026-05-19 15:27:07 +02:00
94303f7e89 fix(core-consent): remove unused ConsentRouter import from router test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 13:23:20 +00:00
e53f35a0c5 feat(core-consent): add handlers and consentRouter tRPC router
Protocol-agnostic handlers (grant, withdraw, isGranted, getCategories)
in core-consent/handlers/ call IConsent methods and return typed results.

consentRouter uses a consent-specific tRPC context (userId + consentFactory)
so each procedure can resolve the per-user IConsent instance at call time.
Auth middleware guards all four procedures and maps UnauthenticatedError →
UNAUTHORIZED via defineErrorMiddleware from core-shared (no local duplicate).

76 tests passing; new handler and router code at 100% branch coverage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 13:22:33 +00:00
ae4e0f2680 chore(work): tick task in 04-core-consent-implementation 2026-05-19 15:01:40 +02:00
b24f0666eb feat(core-consent): add extractAnonymousConsent and migrateAnonymousConsent helpers
Migration helpers let the auth signUp flow transfer anonymous cookie consent
to an authenticated user's record. extractAnonymousConsent parses the raw
Cookie header; migrateAnonymousConsent calls IConsent.grant with
method: "signup-migration" for each granted category, making the migration
traceable in the audit log. No-op when the consent cookie is absent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 12:59:53 +00:00
c346f85bc8 chore(work): tick task in 04-core-consent-implementation 2026-05-19 14:53:51 +02:00
500a163e90 test(core-consent): add missing test coverage and fix diff allowlist
Add symbols.test.ts to cover CONSENT_SYMBOLS constant.
Add recording-consent.test.ts to core-testing (follows the pattern
of all other recording doubles which each have a sibling test file).
Refactor payload-consent.test.ts to extract a makeConsent() helper,
reducing clone groups from 7 to 2.
Add new test to cover grantedAt=null branch in deserializeEntry (withdraw
before any grant → persisted as null → loaded as undefined).
Extend coverage/diff.mjs allowlist for packages/core-testing/ since that
tooling package does not install @vitest/coverage-v8 and therefore produces
no lcov data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 12:48:50 +00:00
7dd46b68b2 feat(core-consent): add PayloadConsent, RecordingConsent and DI binders
Implements the Payload-backed IConsent that reads/writes users.consentState
and emits CONSENT_GRANT/CONSENT_WITHDRAW audit entries via injected auditLog.
Adds RecordingConsent test double in core-testing for unit-test injection.
Adds bindProductionConsent/bindDevSeedConsent DI binders and InMemoryConsent
for dev/seed contexts. Contract tests cover grant/withdraw/isGranted round-trip,
audit entry shape, metadata persistence (bannerVersion/policyVersion/method),
and getCategories reflection of state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 12:39:31 +00:00
5792b7412a chore(work): finish 03-core-consent-foundation 2026-05-19 13:54:40 +02:00
1cab88916a feat(core-eslint): add no-undeclared-consent-check rule (conformance gate 12)
Extends the conformance ESLint layer with the consent-check rule:

- `no-undeclared-consent-check` (warn): `consent.isGranted("X")` in a
  use-case file must match a category declared in `manifest.requiresConsent`;
  also warns when requiresConsent is declared but no isGranted call is found.
- `_manifest-ast.js`: adds `parseManifestFully` which extracts top-level
  `name`, `requiredCores`, `requiresConsent`, and per-use-case maps from the
  manifest AST; `requiresConsent` extraction tested in `_manifest-ast.test.js`.
- `_rule-context.js` / `_rule-schema.js`: shared helpers extracted from the
  existing per-rule files so the new rule can resolve use-case name + feature
  root without duplication.
- Existing rules (`no-undeclared-audit`, `no-undeclared-event-publish`,
  `no-undeclared-analytics-event`) updated to use the shared helpers.
- `plugin.js` + `base.js` register the rule at warn severity.
- CLAUDE.md + conformance-quickref.md: rule count advanced from 11 → 12.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 11:51:30 +00:00
ef9cfd243e docs: seed PRD for security headers + rate-limit + SBOM (ADR-025 Epic C)
Implementation seed for ADR-025 Epic C: six security headers middleware
with nonce-based CSP in core-shared/security (Next + TanStack adapters),
fourth conformance channel for rate-limit in core-shared/rate-limit
(IRateLimit + RateLimited brand + multi-budget manifest field +
no-undeclared-rate-limit ESLint rule), CycloneDX SBOM step in
release-please.yml. auth.signIn backfilled as canonical rate-limit
reference. ADR-023 amendment for SBOM captured. Status: approved —
ready for pnpm work decompose.
2026-05-19 13:09:20 +02:00
9956d73b10 chore(work): tick task in 03-core-consent-foundation 2026-05-19 13:06:52 +02:00
b992fee088 feat(core-consent): extend generator with consent template + fix withCapture brand propagation
- Add consent to CORE_PACKAGE_GENERATORS in turbo/generators/config.ts so
  pnpm turbo gen core-package consent is a valid command (not hand-rollable)
- Create turbo/generators/templates/core-package/consent/ mirroring the
  analytics template shape (AGENTS.md, package.json, tsconfig, turbo, vitest,
  eslint, src/index.ts scaffolds)
- Regenerate packages/core-consent/ from the new template (replaces the
  previous hand-rolled attempt that violated the generator-first rule)
- Add __consentChecked to withCapture PROPAGATED_BRANDS so the brand bubbles
  through the full withSpan→withCapture wrapper chain to the outermost binding
  that assertFeatureConformance reads

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 11:01:17 +00:00
9cb2fa321c feat(core-consent): scaffold package with types, IConsent, withConsent brand wrapper
- Add packages/core-consent with ConsentCategory, ConsentState,
  UserConsentState types and IConsent interface
- Add withConsent wrapper attaching __consentChecked brand at bind time;
  unit tests assert brand attachment and factory passthrough
- Add ConsentChecked<F> type to core-shared/conformance/brands.ts and
  isConsentChecked helper to brand-runtime.ts
- Extend FeatureManifest with requiresConsent?: readonly string[] field
- Extend assertFeatureConformance to require __consentChecked brand when
  requiresConsent.length > 0; synthetic fixture tests cover pass/fail cases
- Propagate __consentChecked in withSpan PROPAGATED_BRANDS so the outermost
  binding carries the brand

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 10:40:40 +00:00
f5d08dc84a chore(work): finish 02-audit-enum-amendment 2026-05-19 12:29:20 +02:00
dd339b11b1 feat(core-shared): extend audit action enum with consent and restriction types
Adds CONSENT_GRANT, CONSENT_WITHDRAW, RESTRICT, UNRESTRICT to the
AuditAction closed enum per GDPR Art. 7 and Art. 18 requirements.

core-consent and core-dsr optional cores (Epic B Stories 03/06) emit
these action types via core-audit's IAuditLog channel; the values must
exist in core-shared's enum before either optional core can be built.
No change to IAuditLog's interface surface — new values flow through
AuditEntry.action automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 10:16:30 +00:00
8cf9f4be98 chore(work): finish 01-subject-linkage-types 2026-05-19 12:13:16 +02:00
f8bb2f4094 feat(core-shared): add subject-linkage types and extend PII defaults
Introduces SubjectLinkKind, SubjectLink, and CollectionSubject types to
packages/core-shared/src/payload/subject-linkage-types.ts, establishes the
ambient CollectionCustom.subject declaration (parallel to custom.pii / custom.retention
from Epic A), and extends PAYLOAD_AUTH_PII_DEFAULTS with processingRestrictedAt and
consentState as DSR-managed excluded fields. Applies the first canonical usage of
custom.subject = { kind: "self", field: "id" } on the auth users collection.
2026-05-19 10:11:09 +00:00
5abf7fe623 chore(work): decompose dsr-consent-and-cookie-banner epic
Generated 1 epic + 11 stories under docs/work/epics/ from the approved
PRD docs/work/prds/dsr-consent-and-cookie-banner.prd.md. Stories cover
subject-linkage types, ADR-018 audit enum amendment, core-consent
foundation + impl + react, core-dsr (4 interfaces), core-api router
composition, core-ui scaffold + CookieConsentBanner, auth signup
migration, and documentation. Ready for `pnpm work dispatch --execute`.
2026-05-19 11:55:05 +02:00
ae886a4499 docs: seed PRD for DSR + consent + cookie banner epic (ADR-025 Epic B)
Implementation seed for ADR-025 Epic B: two new optional cores
(@repo/core-dsr with 4 interfaces, @repo/core-consent with IConsent +
ConsentChecked brand + requiresConsent manifest field), CookieConsentBanner
in core-ui with EU-prominence defaults, subject-linkage types in
core-shared, ADR-018 amendment adding 4 new audit action types
(CONSENT_GRANT/WITHDRAW + RESTRICT/UNRESTRICT). 15 user stories ordered
by the in-epic sequencing hints. Status: approved — ready for
pnpm work decompose.
2026-05-19 11:41:25 +02:00
07caaa1695 chore(work): finish epic compliance-manifests-pii-retention-subprocessors 2026-05-18 22:23:29 +02:00
879b0215c3 docs(compliance): add docs/compliance reference examples and README
Adds docs/compliance/ as the canonical onboarding reference for the
compliance module, covering every field in each generated YAML artifact
with inline annotations and explaining the docs/compliance/ (examples)
vs compliance/ (live artifacts) split.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 20:22:01 +00:00
188625b4a8 chore(work): finish 07-pre-commit-and-ci-integration 2026-05-18 22:16:22 +02:00
239cfcadfa feat(scripts): pre-commit hook + CI gate for compliance drift
Wire pnpm compliance:emit-all into the pre-commit hook (conditional on
staged Payload configs, library traces, or compliance/ files) and add a
hard-fail compliance drift check step to the CI validate job positioned
after pnpm conformance.

Also fix emit-all.mjs: it previously hardcoded --check on every invocation,
so it never actually regenerated artifacts. Now the default mode writes and
--check mode diffs only — matching the pre-commit (write) vs CI (check) split.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 20:14:45 +00:00
add54f14ef chore(work): finish 06-compliance-generator-scripts 2026-05-18 22:12:12 +02:00
7d3125627c fix(scripts): allow .prettierignore in coverage diff gate
.prettierignore is a config file with no executable code. Without this
allowlist entry, pnpm coverage:diff fails with no-coverage-data when
.prettierignore is part of the diff.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 20:08:24 +00:00
b69c5a2112 fix(scripts): exclude generated compliance yml from prettier formatting
Some checks failed
Coverage snapshot / snapshot (push) Has been cancelled
Release Please / release-please (push) Has been cancelled
Sentry PII guard (R31) / pii-guard (push) Has been cancelled
CI / typecheck + lint + boundaries + test + build (push) Has been cancelled
CI / Playwright e2e (push) Has been cancelled
CI / Storybook smoke tests + visual regression (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Prettier was collapsing sub-processors: []<newline>  [] to
sub-processors: [] on commit, causing emit-all --check to fail
immediately after generation. Adding .prettierignore prevents
lint-staged from reformatting these generated artifacts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 20:07:17 +00:00
c333d41a5b feat(scripts): add emit-all orchestrator + initial compliance artifacts
Adds scripts/compliance/emit-all.mjs which runs all three compliance
emitters in --check mode and exits non-zero if any artifact is stale.
Adds compliance:emit-all root package script.

Generates initial compliance/retention-policy.yml and
compliance/sub-processors.yml from the template collections.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 20:05:46 +00:00
3ec30507d3 chore(work): tick task in 06-compliance-generator-scripts 2026-05-18 22:02:54 +02:00
33bac95c41 feat(scripts): add emit-sub-processors compliance script + tests
Adds scripts/compliance/emit-sub-processors.mjs which walks
docs/library-decisions/*.md, filters is-sub-processor: true entries
via frontmatter parsing, merges compliance/sub-processors.manual.yml
(graceful skip if absent), and emits sorted deterministic YAML to
compliance/sub-processors.yml.

- parseFrontmatter: extracts top-level scalars, skips nested blocks
- parseLibraryTraceSubProcessors: discriminated-union filter on
  is-sub-processor flag
- loadManualEntries / parseSimpleYamlList: flat YAML list parser for
  manual entries; injects source: manual
- buildSubProcessors: merge + sort by package name
- renderSubProcessorsYaml: package-first field order, rest alphabetical
- --check and --print modes via shared unifiedDiff from emit-data-map
- 39 unit tests across all exported functions

Wires compliance:sub-processors root package script.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 20:01:06 +00:00
d8dbc99bab chore(work): tick task in 06-compliance-generator-scripts 2026-05-18 21:53:18 +02:00
844b9ee324 feat(scripts): add emit-retention-policy compliance script + tests
Adds scripts/compliance/emit-retention-policy.mjs which walks Payload
collection files, validates purgeSchedule is declared on every
collection, and emits deterministic YAML to
compliance/retention-policy.yml. Supports --print and --check modes.

Wires compliance:retention-policy root package script. Ships 19 unit
tests covering validation, builder, YAML rendering, and diff modes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 19:52:01 +00:00
ab44b2f16d chore(work): tick task in 06-compliance-generator-scripts 2026-05-18 21:47:27 +02:00
cc2bf44fd2 feat(scripts): add emit-data-map compliance script + tests
Adds scripts/compliance/emit-data-map.mjs which walks Payload collection
configs (packages/*/integrations/cms/collections/*.ts), applies
PAYLOAD_AUTH_PII_DEFAULTS + custom.authPii overrides, and emits a
deterministic YAML PII inventory at compliance/data-map.yml.

Supports --print (stdout) and --check (diff vs committed, exit 1 on
mismatch) modes. Ships with 26 unit tests covering happy path, auth
defaults, authPii overrides, --check match/mismatch, and empty
collections. Wired as `compliance:data-map` root package script.

Adds @typescript-eslint/parser to root devDependencies (already in
workspace via core-eslint, now made explicit for scripts/ usage).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 19:44:55 +00:00
3a73634d71 chore(work): finish 05-backfill-template-collections 2026-05-18 21:21:31 +02:00
379772a000 feat(navigation): add retention metadata to header global
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 19:19:54 +00:00
97bf27b6db chore(work): tick task in 05-backfill-template-collections 2026-05-18 21:18:07 +02:00
3b2d618cfc feat(media): add retention metadata to media collection
Adds custom.retention (monthly purge, 90-day post-deletion hard-delete)
to the media Payload collection. No uploadedBy field exists in the
collection so no custom.pii annotation is needed.
2026-05-18 19:16:23 +00:00
68240ad0f3 chore(work): tick task in 05-backfill-template-collections 2026-05-18 21:14:04 +02:00
cc000e1ad4 feat(marketing-pages): add retention metadata to pages and site-settings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 19:12:17 +00:00
b5c16a76c1 chore(work): tick task in 05-backfill-template-collections 2026-05-18 21:09:27 +02:00
a6fc874f11 feat(blog): add retention metadata to articles collection
Monthly purge schedule with 90-day post-deletion hard-delete window.
Part of compliance backfill (Story 05).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 19:08:04 +00:00
2f1aa849e7 chore(work): tick task in 05-backfill-template-collections 2026-05-18 21:05:30 +02:00
a32ff12a69 feat(auth): add PII and retention metadata to users collection
Tag displayName as identification-username PII and declare daily purge
with 30-day post-deletion hard-delete retention. PAYLOAD_AUTH_PII_DEFAULTS
covers email/credentials automatically — no authPii override needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 19:03:58 +00:00
464df9aa9b chore(work): finish 04-retention-purge-job 2026-05-18 20:58:23 +02:00
7ea38bc5b9 feat(core-shared): add retention-purge background job
Adds retention-purge.job.ts to packages/core-shared/src/payload/retention-purge/.
Walks every Payload collection's custom.retention.purgeSchedule, registers one
scheduled job per collection via IJobQueue, queries rows past their activeRetention
period (by createdAt for from-creation, updatedAt for from-last-access), and applies
pseudonymize (null PII fields) or hard-delete per postDeletion.action. Emits one
IAuditLog.record entry per processed row; gracefully skips when auditLog is absent.

Unit tests cover: schedule registration, trigger-type routing, hard-delete branch,
pseudonymize branch, audit emission, graceful auditLog skip, no-activeRetention
short-circuit, and input validation error cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:56:14 +00:00
d326270e1e chore(work): finish 03-adr-022-amendment-and-evaluate-library-skill 2026-05-18 20:46:04 +02:00
98d96d2e19 docs(tooling): add sub-processor discriminated union to ADR-022 and traces
Amends ADR-022 §9 with the `is-sub-processor` / `processes-pii` discriminated
union spec, including the five conditional fields required when a library is a
true GDPR sub-processor. Updates the evaluate-library skill to prompt for these
fields during every trace authoring pass and adds the updated frontmatter
template. Backfills all nine existing library-decision traces with the new
fields; payload gets `processes-pii: true` (self-hosted CMS that stores user
data); all pure in-process libraries get `false / false`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:44:09 +00:00