Design-System Package Governance and Ownership Mapping
Practical 14 - Design-System Package Governance and Ownership Mapping
Related: Chapter 14 · Lecture slides
Objective
Design, package, and govern a shared Design System UI package (@municipal/ui) consumed by a municipal citizen application (apps/citizen-portal) in a monorepo workspace.
By completing this laboratory, you will:
- Architect a Two-Tier Token Pipeline: Separate raw palette constants from semantic intent tokens using CSS Custom Properties.
- Enforce Component Purity: Implement reusable, accessible UI primitives that remain 100% agnostic of municipal domain logic.
- Manage a Breaking API Deprecation Lifecycle: Execute a backwards-compatible SemVer release, providing deprecation console warnings and an automated migration path.
- Define Team Ownership Boundaries: Create a formal RACI governance matrix preventing design system packages from becoming dumping grounds for product-specific code.
Workspace Setup
Initialize a lightweight monorepo workspace:
Configure package.json with native npm/pnpm workspaces:
Stage-by-Stage Implementation
Stage 1: Two-Tier Design Tokens
In packages/ui/src/tokens.css, define raw platform values and semantic intent tokens:
Stage 2: The Domain-Agnostic UI Primitive
In packages/ui/src/Button.tsx, build a primitive button. It must know nothing about permits, tax bills, or citizen records:
Stage 3: Consuming in Product Application
In apps/citizen-portal/src/PermitFeeCard.tsx, the product team composes the primitive into their domain workflow:
Stage 4: Package Boundary & Versioning Governance
Configure packages/ui/package.json to expose a clean, encapsulated public API:
The Package Boundary Rule:
Consumers can only import from exposed entry points (@municipal/ui and @municipal/ui/tokens.css). Internal implementation files (packages/ui/src/internalHelpers.ts) cannot be reached, preserving the platform team’s freedom to refactor internals without breaking consuming apps.
Stage 5: Design System Team Ownership (RACI Matrix)
To eliminate organizational friction, document the RACI Ownership Map in packages/ui/GOVERNANCE.md:
| Architectural Element | Design System Platform Team | Product Feature Teams | UX / Accessibility Council |
|---|---|---|---|
| Raw & Semantic Tokens | Accountable (A) | Consulted (C) | Responsible (R) |
UI Primitives (Button, Modal) | Responsible & Accountable (R/A) | Consulted (C) | Informed (I) |
Domain Components (PermitFeeCard) | Informed (I) | Responsible & Accountable (R/A) | Consulted (C) |
| SemVer Major Releases | Responsible & Accountable (R/A) | Consulted (C) | Informed (I) |
Verification and Testing Matrix
| Test ID | Test Scenario | Verification Procedure | Pass Criteria |
|---|---|---|---|
| PKG-01 | Token Abstraction | Check CSS output for --color-action-primary | Resolves to semantic CSS custom property; raw hex is not hardcoded in component. |
| PKG-02 | Domain Isolation | Grep packages/ui/src/ for “permit” or “tax” | Zero occurrences found; primitives are 100% domain-agnostic. |
| PKG-03 | Deprecation Warning | Render <Button variant="danger"> in test environment | Logs single deprecation warning to console; renders with critical tone styles. |
| PKG-04 | Package Encapsulation | Attempt import from '@municipal/ui/src/internalHelper' | TypeScript & Bundler reject with package export encapsulation error. |
| PKG-05 | Accessibility Baseline | Test <Button isLoading={true}> | Renders aria-busy="true" and disabled attribute. |
Deliverables & Submission Checklist
-
packages/ui/src/tokens.css: Two-tier raw and semantic design tokens with dark-mode remapping. -
packages/ui/src/Button.tsx: Accessible primitive with deprecation handling and loading state. -
packages/ui/package.json: Encapsulated"exports"configuration with explicit CSS side-effects. -
apps/citizen-portal/src/PermitFeeCard.tsx: Consuming domain component. -
packages/ui/GOVERNANCE.md: Documented RACI team ownership matrix.