Malevich

v1.0 architecture

ADR + migration plan

ADR Plan + Migration Plan

Two related artifacts in one document. The ADR plan lists architectural decision records to write, in priority order. The migration plan describes the step-by-step transition from v0.1.0 to v1.0.


Part 1 — ADR plan

Status of existing ADRs

New ADRs to write (in execution order)

ADR-0006 — Component classification by functional role

Documents the four-layer model (Foundations / Elements / Blocks / Sections), the decision tables for layer assignment, and the rationale for treating Avatar as Foundation, Tabs as Element, Alert as Element. References Section 1 + 2 quiz decisions.

Estimated length: 800-1000 words. Priority: critical (foundational architectural decision).

ADR-0007 — Modifier system as cross-cutting layer

Documents the 7 modifier categories, the variants vs modifiers syntactic split (BEM vs data-attributes), namespace separation rule, selective inheritance (rhythm + motion inherit, others don't), applicability matrix as JSON, custom modifier extension API.

Estimated length: 1200-1500 words. Priority: critical.

ADR-0008 — Token tier strict separation

Documents the three-tier model with the explicit rule that components never read foundations directly. Lint enforcement, naming conventions, theme-tier responsibility. References Section 8 quiz decisions.

Estimated length: 800-1000 words. Priority: critical.

ADR-0009 — Semantic typography naming

Documents the rejection of abstract sizes (xl, l, m, s) in favor of role-based naming (hero, statement, title, lead, regular, support). Includes the full token inventory and fluid scaling rule for display sizes. References Section 8 Q8.7.

Estimated length: 600-800 words. Priority: high.

ADR-0010 — Overlays as their own layer

Documents the decision to keep overlays as a discoverable category despite the conceptual elegance of "overlay as mode". File structure, documentation hierarchy, AGENTS.md organization. References Section 6 Q6.1.

Estimated length: 500-700 words. Priority: medium.

ADR-0011 — Iconography as pluggable packs

Documents the rejection of bundled icon library in favor of canonical name registry + adapter API. Default pack (Phosphor), pack switching, CSS mask-image rendering, documentation focus on icon selection principles.

Estimated length: 800-1000 words. Priority: medium.

ADR-0012 — Effects (CSS) vs Shaders (WebGL) split

Documents the two-tier visual enhancement system: CSS-only effects in core (grain, glow, ring, noise, blur), WebGL shaders in opt-in @malevich/shaders package. Explicit fallback contract, progressive enhancement philosophy.

Estimated length: 600-800 words. Priority: low (forward-looking, v2.0 scope).

ADR-0013 — Form subsystem separation

Documents Form-button + Form-divider + Field-group as distinct from generic Button + Divider. Rationale: form context constrains design; separation keeps generic components aesthetically free. References Section 3 Q3.18, Q3.19.

Estimated length: 600-800 words. Priority: medium.

ADR-0014 — Carousel scope discipline

Documents what Carousel ships in v1.0 (scroll-snap, pagination, prev/next) and what doesn't (auto-play, loop, fade, vertical). Why scope was narrowed for v1.0 reliability. References Section 4 Q4.4.

Estimated length: 400-600 words. Priority: low.

ADR-0015 — Card composition pattern

Documents the hybrid approach: one Card, semantic HTML tags (<article>, <aside>, <div>), data-pattern hints, named slots. Rejection of BlogCard/ProductCard/MetricCard multiplication. References Section 4 Q4.1.

Estimated length: 700-900 words. Priority: medium.

ADR writing schedule

Total: 10 new ADRs. With existing 5, the project will have 15 ADRs by v1.0 release.


Part 2 — Migration plan v0.1.0 → v1.0

Migration philosophy

We have no external users. Breaking changes are OK. The migration is internal-only and can be aggressive.

But we have ~150 tests we don't want to lose, and ~10 components with real implementation we don't want to rewrite from scratch. The migration preserves implementation while restructuring.

Migration phases

Phase M-1 — Documentation freeze (1-2 hours)

Before any code changes, capture the current state:

  1. Tag current main as v0.1.0-baseline (already done — tag v0.1.0 exists)
  2. Snapshot packages/components/src/ file structure
  3. Snapshot tokens/{foundations,semantic,component-specific}.json
  4. Snapshot existing test names and counts
  5. Document current modifier usage (.t-* tweaks, current data-attributes)

This baseline is reference for verifying migration completeness.

Phase M-2 — Architectural ADRs (4-8 hours)

Write ADR-0006, ADR-0007, ADR-0008 (the three critical ones). These ADRs:

Output: 3 ADR files committed to llm-wiki/decisions/.

Phase M-3 — Token system migration (8-16 hours)

Most invasive change. Done first because everything else depends on it.

  1. Rewrite packages/core/tokens/foundations.json with proper nested structure (color/space/radius/shadow/font/duration/easing categories)
  2. Rewrite packages/core/tokens/semantic.json with semantic groups (color.text, color.surface, color.border, etc.)
  3. Update packages/core/src/build.ts to emit flat CSS variables from nested JSON
  4. Update packages/core/src/types.ts with new type definitions
  5. Update packages/core/src/resolve.ts for alias resolution in new structure
  6. Update token tests to match new structure
  7. Run codemod over all component CSS to rename existing token references to new names
  8. Verify all components still compile and tests pass

Codemod script: scripts/migrate-tokens-v01-to-v1.mjs that:

Phase M-4 — Modifier system rename (4-8 hours)

  1. Rename "tweak" → "modifier" throughout codebase
  2. Rename "treatment" category → "effect" in design vocabulary
  3. Rename .t- prefix to data-attribute approach
    • Example: .button.+glow-hover (already migrated to .button.t-glow-hover) becomes data-effect="glow" on hover variant
  4. Create modifiers/applicability.json with initial component → modifier mapping
  5. Update existing component CSS to declare modifier namespaces (--{component}-surface-*, --{component}-effect-*)
  6. Update existing components to consume modifier variables correctly

Codemod script: scripts/migrate-modifiers-v01-to-v1.mjs for class renames and CSS variable namespace updates.

Phase M-5 — Component layer reorganization (8-16 hours)

File system moves with import path updates:

  1. Move Avatar:

    • From: packages/components/src/elements/avatar/
    • To: packages/components/src/foundations/avatar/
    • Update: All imports referencing avatar
    • Update: packages/components/src/index.ts exports
    • Update: docs site sitemap (when docs rebuilt)
  2. Move Tabs:

    • From: packages/components/src/blocks/tabs/
    • To: packages/components/src/elements/interactive/tabs/
    • Update: All imports, exports, runtime registrations
  3. Move Alert:

    • From: packages/components/src/blocks/alert/
    • To: packages/components/src/elements/display/alert/
    • Update: All imports, exports
  4. Reorganize remaining Elements into sub-categories:

    • packages/components/src/elements/interactive/ (Button, Tabs)
    • packages/components/src/elements/form/ (Input, Checkbox)
    • packages/components/src/elements/display/ (Badge, Alert)
  5. Update tests to match new file paths (test imports)

  6. Verify all 109 tests still pass after reorganization

Codemod script: scripts/migrate-component-layout-v01-to-v1.mjs for git mv operations and import path updates.

Phase M-6 — Lint rule additions (4-6 hours)

  1. Implement no-foundation-direct-reference stylelint rule in @malevich/lint
  2. Implement modifier-namespace-check stylelint rule
  3. Fix existing no-raw-values Safari border shorthand 1px detection bug
  4. Fix stylelint v16 deprecation (context.fix → fix callback)
  5. Update lint tests for new rules
  6. Run lint over all component CSS — fix any violations introduced by migration
  7. Run full test suite — ensure 0 regressions

Phase M-7 — Component documentation update (8-16 hours)

For each of the 10 v0.1.0 components:

  1. Update <name>.docs.md with new architectural model references
  2. Create sibling <name>.agents.md with:
    • When to use / when not to use
    • Required HTML
    • Variants + modifiers applicability
    • Tokens consumed (by tier)
    • Token-to-component mapping (critical Q8.7-derived addition)
    • Common mistakes agents make
  3. Update _visual-reference.html if any variant changed
  4. Update component-level CSS comments referencing new principle numbers

Phase M-8 — Migration verification (2-4 hours)

  1. Full test suite run — must pass 100% (no regressions from baseline 109 tests)
  2. Lint run — must pass with all new rules
  3. Build run — all packages must build cleanly
  4. Manual smoke test — checkout sample app, render every component, verify visually
  5. Tag as v0.2.0 with comprehensive release notes

Migration deliverables

After M-1 through M-8:

Total estimated time: 40-60 hours of focused work. Realistically 1-2 weeks of evenings.

Migration risks and mitigations

Risk Mitigation
Token rename breaks component CSS Comprehensive codemod with --dry-run mode, manual review
Import path changes break tests Sequential phases, full test suite after each phase
Modifier namespace conflict in cascade Lint rule catches at build, before runtime
Lost work if migration goes wrong Tag v0.1.0-baseline as safe restore point
Documentation drift during migration Update docs.md + agents.md in same commits as code

Migration parallelization

Can be parallelized in CC sessions:

Phases M-7 and M-8 must be sequential (after all migrations) and not parallelizable.


Part 3 — Post-migration: v1.0 implementation plan

After v0.2.0 ships (migration complete), v1.0 work begins. This is 43 net-new components plus documentation site rebuild.

v1.0 implementation phases

Phase V-1 — Foundations completion (40-60 hours)

Build Icon (with pack system), Divider, Spinner, Skeleton, Dots, Image. Avatar already migrated. Typography already exists as classes (extend with display.hero/statement/title fluid sizes + semantic role naming).

Phase V-2 — Form subsystem (60-80 hours)

Build Field-group, Label, Textarea, HelperText, Error, Select (native styled), Radio-group, Checkbox-group, Form-button, Form-divider. This is one cohesive subsystem; ship together.

Phase V-3 — Remaining Interactive + Display Elements (40-60 hours)

Build Button-group, Switch, Toggle, Kbd. Update Button to 5 variants. Build Tag, Tags-group, Avatar-group, Code (inline).

Phase V-4 — Blocks (60-80 hours)

Build Accordion, Carousel (minimal scope), Breadcrumb, Code block, Quote block, State (4 variants). Card already exists; update with semantic-tag + data-pattern approach.

Phase V-5 — Layout Sections (40-60 hours)

Build Block, Split, Grid, Stack layouts. These are CSS-heavy, JS-light. Container query and viewport query architecture is the focus.

Phase V-6 — Ready Sections (60-80 hours)

Build Hero (with patterns), CTA, Site-header (with shape/surface/background/behavior modifiers), Site-footer. Site-header is most complex — many modifier combinations.

Phase V-7 — Overlays expansion (40-60 hours)

Build Sheet, Popover (with Floating UI), Toast, Notifications. Dialog + Tooltip already exist. Integrate Floating UI as runtime dependency.

Phase V-8 — Icon packs (20-40 hours)

Build @malevich/icons-default (Phosphor adapter), @malevich/icons-lucide, @malevich/icons-tabler. Document canonical name registry and pack adapter API.

Phase V-9 — Documentation site rebuild (80-120 hours)

Vanilla Astro + MDX. All 53 component pages. Foundations + playbook + decisions + examples sections. Theme switcher. Code tabs with AGENTS.md. Sandbox iframes. Cloudflare Pages deployment.

This is the largest single phase. Can be split into sub-tracks (scaffold + theme, content collections, component pages, foundations pages, deployment).

Phase V-10 — Tooling polish (20-30 hours)

@malevich/cli for project scaffolding. Stylelint rules for tier-respect. Build pipeline upgrades. AGENTS.md auto-generation from applicability matrix.

Total v1.0 estimated time: 460-670 hours after v0.2.0 migration. This is months of work for one developer; with CC parallel sessions and Figma reference, achievable in 3-4 months.


Migration vs new work — what unblocks what

The migration (v0.2.0) unblocks v1.0 component work. Without the new architecture in place, building new components produces code in the old model.

Within v0.2.0, the order matters:

  1. Token migration → unblocks modifier work
  2. Modifier rename → unblocks lint rules
  3. Component moves → independent
  4. Lint rules → blocks lint testing

Within v1.0, phases are mostly independent. Foundations (V-1) is the only phase that blocks others — Icon system must work before Site-header can use icons, etc.

The full chain:


Going live

v0.2.0 release: Tag, write release notes referencing migration, push to GitHub. No public announcement (we're not public yet).

v1.0 release: Big bang launch. Documentation site live at malevich.design (transitioned from malevich.oleg.design). Manifesto publication. HN/Reddit/Twitter posts. Designer outreach. Ukrainian media outreach (cultural anchor story).

Pre-v1.0 development stays private. The architectural decisions in this document are sufficient to start building without consulting the public.