feat: finish token core (milestone 2) #2

Merged
marti merged 4 commits from feature/m2-finish-token-core into main 2026-10-26 23:45:19 +01:00
Owner

Milestone 2 from docs/roadmap/v1-remaining-work.md.

Summary

 PATCH /orgs/:orgId/projects/:id
   name, description, designSystemId, orgAccess
+  pinnedVersion     # a version of the linked design system, or null = track latest
+  themeOverrides    # saved even when broken
 Project (list and single)
+  pinnedVersion, latestVersion, behind, themeOverrides
 ProjectDetail (GET / POST / PATCH one project)
+  overrideValidation   # validateDocument(pinned-or-latest version, overrides); null without DS read access
 Draft
+  hasUnpublishedChanges   # tokens or guidelines differ from the latest version
 validateDocument(document, overrides)
+  unknown_mode warning for overrides of a mode the version lacks
<DesignSystemPage>
  <DraftPanel>          revision, last editor, issues, unpublished changes, <PublishDialog>
  <GuidelinesPanel>     overview, voice and tone, per-component usage/dos/don'ts -> PATCH draft
  <VersionsPanel>       versions + changelogs, reset draft to a version
<ProjectPage>
  <VersionPicker>       track latest or a version, "behind latest" warning
  <OverridesPanel>      path + mode + token JSON, override report shown below

Decisions are in ADR 0008: linking another design system clears the pin (overrides stay), broken overrides are saved and reported, the report is hidden from members who cannot read the design system, and version numbers are visible to every project reader. The web app now depends on @designbase/core (for bumpVersion, and the editor in milestone 3), so the web Dockerfile and compose.dev.yaml copy or mount it.

trail check flags 5 files against the "token documents are json, not jsonb" learning. These are keyword matches only. No column changed, and docs/database.md now states that token documents are json.

Evidence

"Done when" scenario, apps/api/test/projects.test.ts:

PATCH draft { guidelines }              -> saved, included in 0.1.0
publish 0.1.0; set color.brand.600 red; publish 0.2.0
PATCH project { pinnedVersion: 0.1.0 }  -> { pinnedVersion: 0.1.0, latestVersion: 0.2.0, behind: true }
PATCH project { themeOverrides.modes.dark.color.primary.background = green }
GET project/tokens?mode=dark            -> version 0.1.0, primary.background = green (layer override-mode)
GET project/tokens?mode=light           -> primary.background unchanged, brand.600 not red (pinned)

There are also API tests for an unknown version (400), a malformed version (400), a version of another design system, pinning with no design system linked (409), the pin clearing when the link changes, broken overrides being saved and reported, viewers being refused (403), the report being hidden without design system access, and hasUnpublishedChanges. Web tests (Testing Library + MSW) cover the publish dialog's blocked state (errors listed, button disabled, no POST) and its success state, plus the guidelines save and its 409, version reset, the version picker and behind warning, and a dark-only override with its returned issue.

  • Before: core 41, API 37, web 16 tests
  • After: core 42, API 45, web 36 tests passing; pnpm lint and pnpm typecheck clean; the web Docker image builds

Merge Danger

Door: two-way

No migration: the pinned_version_id and theme_overrides columns already existed. The API only gains fields; nothing is removed.

Blast Radius: small

Project responses gain required fields, so any client that parses them strictly needs the new shared schema. The only such client is the web app in this PR. Single-project responses now resolve every mode of the version to validate overrides, which adds a little latency to project pages.

🤖 Generated with Claude Code

Milestone 2 from `docs/roadmap/v1-remaining-work.md`. ## Summary ```diff PATCH /orgs/:orgId/projects/:id name, description, designSystemId, orgAccess + pinnedVersion # a version of the linked design system, or null = track latest + themeOverrides # saved even when broken Project (list and single) + pinnedVersion, latestVersion, behind, themeOverrides ProjectDetail (GET / POST / PATCH one project) + overrideValidation # validateDocument(pinned-or-latest version, overrides); null without DS read access Draft + hasUnpublishedChanges # tokens or guidelines differ from the latest version validateDocument(document, overrides) + unknown_mode warning for overrides of a mode the version lacks ``` ```text <DesignSystemPage> <DraftPanel> revision, last editor, issues, unpublished changes, <PublishDialog> <GuidelinesPanel> overview, voice and tone, per-component usage/dos/don'ts -> PATCH draft <VersionsPanel> versions + changelogs, reset draft to a version <ProjectPage> <VersionPicker> track latest or a version, "behind latest" warning <OverridesPanel> path + mode + token JSON, override report shown below ``` Decisions are in ADR 0008: linking another design system clears the pin (overrides stay), broken overrides are saved and reported, the report is hidden from members who cannot read the design system, and version numbers are visible to every project reader. The web app now depends on `@designbase/core` (for `bumpVersion`, and the editor in milestone 3), so the web Dockerfile and `compose.dev.yaml` copy or mount it. `trail check` flags 5 files against the "token documents are `json`, not `jsonb`" learning. These are keyword matches only. No column changed, and `docs/database.md` now states that token documents are `json`. ## Evidence "Done when" scenario, `apps/api/test/projects.test.ts`: ```text PATCH draft { guidelines } -> saved, included in 0.1.0 publish 0.1.0; set color.brand.600 red; publish 0.2.0 PATCH project { pinnedVersion: 0.1.0 } -> { pinnedVersion: 0.1.0, latestVersion: 0.2.0, behind: true } PATCH project { themeOverrides.modes.dark.color.primary.background = green } GET project/tokens?mode=dark -> version 0.1.0, primary.background = green (layer override-mode) GET project/tokens?mode=light -> primary.background unchanged, brand.600 not red (pinned) ``` There are also API tests for an unknown version (400), a malformed version (400), a version of another design system, pinning with no design system linked (409), the pin clearing when the link changes, broken overrides being saved and reported, viewers being refused (403), the report being hidden without design system access, and `hasUnpublishedChanges`. Web tests (Testing Library + MSW) cover the publish dialog's blocked state (errors listed, button disabled, no POST) and its success state, plus the guidelines save and its 409, version reset, the version picker and behind warning, and a dark-only override with its returned issue. - **Before:** core 41, API 37, web 16 tests - **After:** core 42, API 45, web 36 tests passing; `pnpm lint` and `pnpm typecheck` clean; the web Docker image builds ## Merge Danger **Door:** two-way No migration: the `pinned_version_id` and `theme_overrides` columns already existed. The API only gains fields; nothing is removed. **Blast Radius:** small `Project` responses gain required fields, so any client that parses them strictly needs the new shared schema. The only such client is the web app in this PR. Single-project responses now resolve every mode of the version to validate overrides, which adds a little latency to project pages. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
PATCH /projects/:id accepts pinnedVersion (a version of the linked design
system, cleared when the design system changes) and themeOverrides. Project
responses carry pinnedVersion, latestVersion, behind and themeOverrides;
single-project responses add overrideValidation, the report of the overrides
against the version they apply to. Drafts report hasUnpublishedChanges.
Overrides for modes the version lacks are unknown_mode warnings. ADR 0008.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The design system page shows the draft's revision, last editor, validation
summary and unpublished changes; a publish dialog driven by the publish
preview (blocked with the error list when the draft is invalid); the version
list with changelogs and reset-to-version; and a guidelines editor that saves
through PATCH draft and reloads on revision conflicts. The web app now
depends on @designbase/core for version arithmetic, so the web image copies it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Projects pick "track latest" or a specific version, warn when pinned behind
the latest, and edit theme overrides per token and mode as JSON, with the
override validation report shown under the editor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs: tokens, versions and project overrides
All checks were successful
ci / check (pull_request) Successful in 2m26s
05293052b1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
marti merged commit 19ef9fbcfe into main 2026-10-26 23:45:19 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marti/designbase!2
No description provided.