Imported from duc01226/easy-claude (
.agents/skills/architecture-design/SKILL.md). Install upstream withnpx skills add duc01226/easy-claude --skill architecture-design. Copyright stays with the author.
Codex compatibility note:
- Invoke repository skills with
$skill-namein Codex; this mirrored copy rewrites legacy Claude/skill-namereferences.- Task tracker mandate: BEFORE executing any workflow or skill step, create/update task tracking for all steps and keep it synchronized as progress changes.
- User-question prompts mean to ask the user directly in Codex.
- Ignore Claude-specific mode-switch instructions when they appear.
- Strict execution contract: when a user explicitly invokes a skill, execute that skill protocol as written.
- Subagent authorization: when a skill is user-invoked or AI-detected and its protocol requires subagents, that skill activation authorizes use of the required
spawn_agentsubagent(s) for that task.- Do not skip, reorder, or merge protocol steps unless the user explicitly approves the deviation first.
- For workflow skills, execute each listed child-skill step explicitly and report step-by-step evidence.
- If a required step/tool cannot run in this environment, stop and ask the user before adapting.
Codex Project-Reference Loading (No Hooks)
Codex uses static project-reference loading instead of runtime-injected project docs. When coding, planning, debugging, testing, or reviewing, open project docs explicitly using this routing.
Always read:
docs/project-config.json(project-specific paths, commands, modules, and workflow/test settings)docs/project-reference/docs-index-reference.md(routes to the fulldocs/project-reference/*catalog)docs/project-reference/lessons.md(always-on guardrails and anti-patterns)
Missing/stale context route: If docs/project-config.json, the docs index, lessons.md, CLAUDE.md, AGENTS.md, or any task-required reference doc is missing or stale, auto-run $project-init or the narrow setup route ($project-config, $docs-init, $scan-all, $scan --target=<key>, $claude-md-init) before ordinary project-specific work. If Codex mirrors or AGENTS.md are missing/stale, ask the user to run $sync-codex; do not auto-run it.
Situation-based docs:
- Project structure/architecture/tech-stack/deployment/setup (any layer — backend, frontend, or infra):
project-structure-reference.md - Backend/CQRS/API/domain/entity changes:
backend-patterns-reference.md,domain-entities-reference.md - Frontend/UI/styling/design-system:
frontend-patterns-reference.md,scss-styling-guide.md,design-system/README.md - Spec authoring,
docs/specs/pathing, or TC format:feature-spec-reference.md,spec-system-reference.md,spec-principles.md - Behavior/public-contract changes or spec-test-code sync:
workflow-spec-test-code-cycle-reference.mdplus the spec docs above - Derived spec indexes/ERDs/reimplementation guides:
spec-system-reference.mdand source Feature Specs underdocs/specs/ - Integration test implementation/review:
integration-test-reference.md - E2E test implementation/review:
e2e-test-reference.md - Code review/audit work:
code-review-rules.mdplus domain docs above based on changed files
Do not read all docs blindly. Start from docs-index-reference.md, then open only relevant files for the task.
[BLOCKING] Execute skill steps in declared order. NEVER skip, reorder, or merge steps without explicit user approval. [BLOCKING] Before each step or sub-skill call, update task tracking: set
in_progresswhen step starts, setcompletedwhen step ends. [BLOCKING] Every completed/skipped step MUST include brief evidence or explicit skip reason. [BLOCKING] If Task tools are unavailable, create and maintain an equivalent step-by-step plan tracker with the same status transitions.
Quick Summary
Goal: As solution architect, deliver a complete, evidence-backed, user-validated architecture decision report covering ALL concerns (backend, frontend, design patterns, library ecosystem, testing, CI/CD, deployment, monitoring, code quality, dependency management) — every concern researched with 3+ options, every recommendation carrying confidence % + cited evidence, every decision user-confirmed — so implementation proceeds on sound, owned architectural choices.
Summary:
-
Testability contract: resolve Unit/Integration/System/E2E applicability from runner/config evidence; record owner/root/data, copy-ready full + focused commands, zero-match behavior, CI/simple-Windows entry, unique run/data identity, and repeat proof; unresolved applicable fields block handoff, while non-applicable tiers require evidence-backed
N/A. -
Decide mode FIRST (Step 1): greenfield researches every concern from scratch; brownfield reads reference docs + accepted ADRs, constrains research to existing stack — NEVER re-litigate a settled ADR-recorded decision without superseding-ADR rationale.
-
Rank every decision by REVERSIBILITY first (Step 2): one-way door (data model, tenancy, consistency model, service boundaries, public contracts, sync-vs-async) → ADR + user validation MANDATORY; two-way door → decide and move. — why: architecture IS the set of decisions expensive to reverse; treating a one-way door as reversible is the costliest error this skill can make.
-
Drive style choice with NUMBERS, not adjectives: quantify Step-2 quality-attribute scenarios (latency p95/p99, throughput, SLO, RPO/RTO, data growth, concurrency); pick ≤3 DRIVING attributes and name which ones you SACRIFICE; any unknown target becomes explicit
Unresolved question, never a silent guess. -
Profile the workload before selecting a scaling technique: read/write ratio · sustained/peak RPS · query shapes · data size/growth · burstiness/hot keys · consistency/staleness · user geography. Escalate through the smallest reversible rung: measure/tune → choose vertical and/or stateless horizontal scale from headroom + availability needs → read/write-specific tactics → partition/shard LAST. — why: a scalable product is a sequence of evidenced bottleneck removals, not a shopping list of distributed components.
-
Simplicity is the default; complexity must be BOUGHT with a measured requirement — modulith-first, distribute only against a named + measured extraction trigger (Step 3A). Reason FROM
.claude/docs/architecture-knowledge.md(laws, coupling taxonomy, style triggers, trade-off + anti-pattern catalogs) — never from familiarity or fashion. -
Every concern needs 3+ researched options with cited evidence (stars, last release, downloads, CVE scan) + confidence % — familiarity alone never sufficient grounds for a recommendation.
-
Interrogate before deciding, DESIGN IT TWICE, then self-audit: run the 15-question pre-decision script (§20.1) on every one-way door (Step 2-2) · produce ≥2 MATERIALLY different candidates per one-way door before choosing (Step 3A) · run the 11 thinking red flags (§20.3) against your own draft before emitting. Prescribe the TACTIC (§2), never the product. — why: a first-idea design with no rejected alternative and no named falsifier is a belief, not a decision.
-
Produce the two binding downstream contracts or the chain breaks: emit an ADR per hard-to-reverse decision (
architecture-reviewCat 9 enforces) and the Scaffold Handoff tool-choices table (scaffold/harness-setupconsume), then run the MANDATORY Step-12 user-validation interview before confirming. -
Main steps/tasks (run in order, track each): 1 Load Context (+pick greenfield/brownfield mode) → 2 Derive Architecture Requirements (+workload profile/scaling ladder, reversibility ranking, ≤3 driving attributes, 6-part quality-attribute scenarios, 2-2 pre-decision interrogation, user-validate) → 3A Backend Styles (selection procedure incl. DESIGN IT TWICE + extraction triggers) → 3B Backend Design Patterns → 3C Data & Consistency Architecture (store/substrate per access pattern, replication/failover, cache contract, consistency + staleness, transaction boundary, tenancy, partitioning, migrations, retention) → 3D Integration & API Architecture (sync-vs-async + acceptance state, API/edge cache style, versioning, contract tests, outbox, idempotency, event granularity) → 4 Frontend Architecture (styles + patterns) → 4B UI System Architecture (styling/tokens/components/responsive, user-validate; skip if backend-only) → 5 Library Ecosystem Research (3 options/concern) → 6 Testing Architecture → 7 CI/CD & Deployment (+expand–contract migrations, backward AND forward compat) → 8 Observability & Monitoring (signal roles + sampling/cardinality) → 9 Code Quality + Scaffold Handoff table → 10 Dependency Risk Assessment → 11 Generate Report + emit ADRs → 12 User Validation Interview (8-12 questions, mark
confirmed) → Next Steps + always-offer council escalation. — why: AI keeps forgetting the skill's own steps; this is the recovery anchor.
Workflow (12 steps):
- Load Context — Read domain model, tech stack, business evaluation, refined PBI
- Derive Architecture Requirements — Profile workload + ordered scaling ladder, rank reversibility, pick ≤3 driving attributes, quantify 6-part scenarios, run 2-2 pre-decision interrogation on every one-way door
- Backend Architecture — 3A styles (selection procedure) · 3B design patterns · 3C data & consistency · 3D integration & APIs
- Frontend Architecture — Research top 3 frontend architecture styles + design patterns
- Library Ecosystem Research — Best-practice libraries per concern (validation, caching, logging, utils, etc.)
- Testing Architecture — Unit, integration, E2E, performance testing frameworks + strategy
- CI/CD & Deployment — Pipeline design, containerization, orchestration, IaC
- Observability & Monitoring — Logging, metrics, tracing, alerting stack
- Code Quality & Clean Code — Linters, analyzers, formatters, enforcement tooling
- Dependency Risk Assessment — Package health, obsolescence risk, maintenance cost
- Generate Report — Full architecture decision report with all recommendations
- User Validation — Present findings, ask 8-12 questions, confirm all decisions
Key Rules:
- MANDATORY IMPORTANT MUST ATTENTION research minimum 3 options per architecture concern with web evidence
- MANDATORY IMPORTANT MUST ATTENTION include confidence % with evidence for every recommendation
- MANDATORY IMPORTANT MUST ATTENTION run user validation interview at end (never skip)
- Delegate to
solution-architectagent for complex architecture decisions - All claims must cite sources (URL, benchmark, case study, or codebase evidence)
- Base every recommendation on evidence, never on familiarity alone
Be skeptical. Apply critical thinking, sequential thinking. Every claim needs traced proof, confidence percentages (Idea should be more than 80%).
Inputs & Handoffs (consume vs produce)
Skill sits mid-workflow — consumes settled upstream decisions, produces artifacts downstream steps build on. Do NOT re-derive what upstream step already owns; do NOT leave downstream consumer without its needed artifact. — why: re-deriving settled decisions wastes effort and risks divergence from the recorded choice.
| Consumes (read, don't re-derive) | From | Produces (named deliverable) | Consumed by |
|---|---|---|---|
| Bounded contexts, aggregates, domain events, ERD | domain-analysis |
Architecture decision report ({plan-dir}/research/...) |
plan, plan-execute |
| Confirmed languages/frameworks/databases | tech-stack-research |
Confirmed decisions ({plan-dir}/phase-02b-architecture.md) |
plan, scaffold |
| Expected scale, compliance, budget constraints | business-evaluation |
Scaffold Handoff table (tooling + fitness rules) | scaffold, harness-setup |
| Existing stack/patterns/ADRs (brownfield) | reference docs, docs/adr/** |
ADRs for hard-to-reverse decisions (docs/adr/) |
architecture-review (conformance) |
If upstream artifact missing, capture minimum needed here and note gap — NEVER silently re-run full upstream analysis. — why: a silent re-run hides the missing-input gap that the owning step should resolve.
Step 1: Load Context
Mode (decide first): Greenfield (new project, e.g. via
workflow-greenfield-init) → research every concern from scratch, full 3-options-per-concern. Brownfield (large feature in existing codebase, e.g.workflow-big-feature) → FIRST read project reference docs + accepted ADRs, constrain research to existing stack/patterns, propose changes only where new requirement genuinely outgrows them — NEVER re-litigate settled ADR-recorded decision without superseding-ADR rationale. — why: re-deciding a recorded choice churns the codebase and breaks downstream conformance checks.
Read artifacts from prior workflow steps (search plans/ and team-artifacts/):
- Domain model / ERD (complexity, bounded contexts, aggregate count)
- Tech stack decisions (confirmed languages, frameworks, databases)
- Business evaluation (scale, constraints, compliance)
- Refined PBI (scope, acceptance criteria)
- Discovery interview (team skills, experience level)
Extract, summarize:
| Signal | Value | Source |
|---|---|---|
| Bounded contexts | ... | domain model |
| Aggregate count | ... | domain model |
| Cross-context events | ... | domain model |
| Confirmed tech stack | ... | tech stack phase |
| Expected scale | ... | business eval |
| Team architecture exp. | ... | discovery |
| Compliance requirements | ... | business eval |
| Real-time needs | Yes/No | refined PBI |
| Integration complexity | Low/Med/High | domain model |
| Deployment target | ... | business eval |
Step 2: Derive Architecture Requirements
Reason FROM the knowledge body, not from memory.
.claude/docs/architecture-knowledge.mdis AUTHORITATIVE for architecture laws (CAP/PACELC, Conway, Amdahl, USL, Little, Gall, Hyrum, Parnas), the coupling taxonomy + four coupling dimensions, style-selection triggers, the trade-off cheat sheet, and the ~100-entry anti-pattern catalog. Read the sections relevant to this design before recommending. Honor the catalog's provenance markers in §3/§8/§9/§10 — a row (or section banner) marked— VERIFYis an UNVERIFIED assertion, so cite it as a hypothesis to check against the named source where one is named (a[model-knowledge]row names none — check the project's own docs or a primary source instead), NEVER as settled fact in a recommendation. The project's own reference docs and accepted ADRs OUTRANK that catalog on any conflict — the catalog supplies universal reasoning, the project supplies binding convention. — why: universal names hardcoded as project rules rot against real repos.
2-0: Rank every decision by REVERSIBILITY (do this FIRST)
Architecture = the set of decisions expensive to reverse; everything cheap to reverse is design — leave it to implementers. Classify each decision BEFORE researching it, because the classification sets how much rigour it earns.
| Class | Meaning | Required treatment |
|---|---|---|
| One-way door | Reversal costs a migration, a rewrite, or a breaking change to consumers | ADR (Step 11) + user validation (Step 12) MANDATORY — research 3+ options, name the rejected alternative AND the measurable revisit trigger |
| Two-way door | Reversal is a refactor inside one module | Decide, record one line, move on — NEVER burn a validation question on it |
One-way doors (assume MANDATORY ADR unless proven otherwise): data model + primary-key strategy · tenancy model · consistency model per read path · sync-vs-async at a boundary · public API/event contract · service boundary lines · cloud-primitive lock-in · auth/identity model · data residency + retention.
MANDATORY IMPORTANT MUST ATTENTION never treat a one-way door as a two-way door to save a step — why: an unreviewed irreversible decision is the single most expensive failure mode of this skill, and it surfaces months later as a migration.
Map signals to architecture constraints:
| Signal | Architecture Requirement | Priority |
|---|---|---|
| Many bounded contexts | Clear module boundaries, context isolation | Must |
| High scale | Horizontal scaling, stateless services, caching strategy | Must |
| Complex domain | Rich domain model, separation of domain from infra | Must |
| Cross-context events | Event-driven communication, eventual consistency | Must |
| Small team | Low ceremony, fewer layers, convention over configuration | Should |
| Compliance | Audit trail, immutable events, access control layers | Must |
| Real-time | Event sourcing or pub/sub, WebSocket/SSE support | Should |
| High integration complexity | Anti-corruption layers, adapter pattern, API gateway | Should |
Quality-Attribute Scenarios (quantify — these drive the style choice)
Qualitative "Must/Should" cannot decide, e.g., modular monolith vs microservices. Capture measurable targets; ask user for any unknown by asking the user directly (guess acceptable only when labelled an assumption with confidence %). These targets become ADR-recorded budgets architecture-review Category 9 later checks changes against. — why: a style chosen without numbers is a guess, not an enforceable decision.
| Quality attribute | Scenario (stimulus → measurable response) | Target (fill in) |
|---|---|---|
| Latency | p95 / p99 response time for the hottest read and write paths | e.g. p99 < 300ms |
| Throughput | Sustained req/s and peak burst the system must absorb | e.g. 500 rps peak |
| Availability / SLO | Target uptime and error budget | e.g. 99.9% |
| Data durability (RPO) | Max acceptable data loss on failure | e.g. ≤ 5 min |
| Recovery (RTO) | Max acceptable time to restore service | e.g. ≤ 30 min |
| Data-volume growth | Row/document/event growth → storage, index, partition strategy | e.g. 10M rows/yr |
| Concurrency | Concurrent users/sessions and contention hot spots | e.g. 2k concurrent |
| Compliance/retention | Regulated data, retention window, residency, audit | e.g. GDPR, 7yr |
| Cost unit economics | $/request, $/tenant, $/MAU — and whether unit cost RISES with scale |
e.g. <$0.002/req |
Scenario template — all SIX parts, none optional: [SOURCE: who/what triggers] [STIMULUS: the event] on [ARTIFACT: which component] under [ENVIRONMENT: the conditions] SHALL produce [RESPONSE] within [MEASURE: threshold + instrument]. "Must be scalable" decides nothing; "5,000 concurrent checkout sessions at 400 rps SHALL complete p99 < 800 ms, ≤0.1% errors, verified by the CI k6 profile" selects a structure.
MUST ATTENTION a scenario missing SOURCE or ARTIFACT is untestable — you cannot write a fitness function for "the system" under "load", so name the actor and the component. — why: an unattributed scenario gets no owner, no test and no budget, so it is never verified and silently degrades.
Rule: any target left unknown is explicit Unresolved question (Step 11), NEVER a silent omission — an architecture chosen without scale numbers is a guess, not a decision.
Workload Profile + Scaling Ladder (MANDATORY before technique selection)
Record read:write ratio · sustained/peak RPS or events/s · dominant query/write shapes · dataset size + growth · payload size · burst duration · hot-key/tenant skew · user regions · latency percentile targets · consistency/staleness tolerance. For every proposed scaling component, name the measured bottleneck it removes and the next bottleneck it creates.
| Order | Use when evidence shows | First tactic | Purchase price |
|---|---|---|---|
| 1. Measure + tune | Baseline unknown or slow path unprofiled | Query/plan analysis, indexes, batching, pooling, compression | Engineering time; lowest reversibility cost |
| 2A. Vertical scale | One node remains simplest and headroom exists | More CPU/RAM/IOPS; tune runtime/database | Hardware ceiling; remaining SPOF without redundancy |
| 2B. Horizontal app scale | Availability or aggregate compute requires replicas and the path can be stateless | Replicas + redundant load balancing + health checks | Coordination, externalized state, deployment complexity |
| 4. Read-path scale | High read ratio or global read latency | Cache/CDN/read replicas/read models | Invalidation, lag, read-your-writes, cache-key correctness |
| 5. Write-path scale | Bursty ingest or heavy work need not finish inline | Batching, durable queue + workers; LSM store for sustained write-heavy known-query workloads | Accepted ≠ completed, retries/idempotency/backpressure; compaction/read amplification |
| 6. Partition/shard | Earlier rungs proven insufficient by capacity measurements | Query-aligned partition key + reshard plan | Cross-shard queries/transactions, hotspots, hard reversal |
MANDATORY IMPORTANT MUST ATTENTION NEVER jump to sharding, multi-region writes, or an extra datastore without evidence that earlier rungs cannot meet the quantified target — why: these are hard-to-reverse operational systems, not generic performance upgrades.
Move each attribute with a TACTIC, not a product. Once a target is unmet or at risk, select the mechanism from the tactics inventory in .claude/docs/architecture-knowledge.md §2 (availability · performance · modifiability · security · testability · usability) — "bulkhead a pool per dependency" is a design decision; "add Kubernetes" is a shopping list. — why: the tactic is portable across stacks and makes the trade-off legible, the product imports costs nobody asked for.
2-1: Pick ≤3 DRIVING attributes — and name what you SACRIFICE
Quality attributes CONFLICT, and that conflict IS the architecture: consistency↔availability · latency↔durability · flexibility↔simplicity · security↔usability · cost↔redundancy · performance↔modifiability.
MANDATORY IMPORTANT MUST ATTENTION name at most 3 DRIVING attributes and explicitly record which attributes are being SACRIFICED to buy them — a design claiming to maximize everything has decided nothing — why: unnamed sacrifices resurface as production surprises nobody agreed to.
| Field | Record |
|---|---|
| Driving attributes (≤3) | ... + the quantified target for each (from the table above) |
| Explicitly sacrificed | ... + the acceptable degradation, e.g. "search may lag ≤5 s" |
| Trade-off purchased | Use the "buy this / pay with this" table in .claude/docs/architecture-knowledge.md §19 — state cost, never just benefit |
Availability arithmetic (compute it, never assert it): dependencies in a request path MULTIPLY — five 99.9% deps ⇒ ~99.5% (≈43 h/yr down). Redundancy in PARALLEL adds 9s only when failure modes are genuinely independent; shared config, control plane, DNS and the deploy pipeline are the usual hidden serial term. Ladder: 99% = 3.65 d/yr · 99.9% = 8.77 h · 99.95% = 4.38 h · 99.99% = 52.6 min · 99.999% = 5.26 min.
Cost is a quality attribute, not a later phase. Model unit economics now — an architecture whose UNIT cost RISES with scale fails eventually regardless of elegance. Biggest web-system drivers: egress + cross-AZ/cross-region traffic · idle over-provisioned compute · unbounded log/metric/trace retention and cardinality · per-request managed-service pricing at steady high volume · always-on non-prod. Serverless vs always-on inverts with utilization — model it, don't assume it.
MANDATORY IMPORTANT MUST ATTENTION validate derived requirements with user by asking the user directly before proceeding.
2-2: Pre-Decision Interrogation (MANDATORY for every one-way door from 2-0)
Answer the 15-question pre-decision script in .claude/docs/architecture-knowledge.md §20.1 for each one-way door BEFORE researching options. Record answers in the Step 11 report; any question answered "unknown" becomes an Unresolved question, never a silent gap.
The five that most often expose a wrong decision — never skip these:
| # | Question | Why it changes the answer |
|---|---|---|
| 3 | Is this a one-way or two-way door, and what makes it so? | Sets how much rigour the decision earns; misclassification is this skill's most expensive failure |
| 5-6 | Expected load NOW and at 10× — and what breaks FIRST? | Names the actual bottleneck instead of the imagined one; 10×, never 1000× |
| 8 | What is the consistency requirement PER read path, and what staleness is acceptable? | Consistency is decided per path, never once globally |
| 14 | What existing thing could be used instead of building? | Generic subdomains (auth, billing, notifications, search) are the top source of wasted architecture budget |
| 15 | What would have to be TRUE for this to be the WRONG choice — and how would I detect it? | Becomes the ADR's measurable revisit trigger |
MANDATORY IMPORTANT MUST ATTENTION a one-way door with no answer to question 15 is a BELIEF, not a decision — NEVER emit its ADR without a named falsifier and a measurable revisit trigger. — why: with no trigger nobody ever revisits it, so the decision outlives the constraints that justified it.
Architecture & Scalability Scorecard Inputs (feeds architecture-scalability-review)
Record these decisions now so the init-time architecture-scalability-review scorecard (mode=init) can grade them later against enforceable mechanisms, not intent. Each row is a design decision, not a finding — capture the choice AND where it is enforced. Leave any unknown as explicit Unresolved question (Step 11), never a silent omission. — why: a scorecard can only grade decisions actually recorded with an enforcement home.
| Scorecard input | Design prompt (decide + record where enforced) | Enforcement handoff |
|---|---|---|
| Build & CI scalability | As the codebase grows, how are build/CI times kept bounded? Decide incremental builds, changed/affected-only detection, local + remote cache strategy, and CI test/build parallelism. Name the build-system fit (single-package vs monorepo tool such as Nx / Turborepo / Bazel) as an evaluated option, not a default. | Step 7 (CI/CD provider parallelism + caching) |
| Horizontal scaling budgets | From the Step 2 scale targets, decide stateless app nodes, load balancing, caching tiers, async/queue + back-pressure, DB scale plan (sharding/partitioning/replication), connection pooling, rate limits, and a SPOF scan of every single-instance dependency. | ADR + Step 8 observability SLOs |
| Strategic DRY | Decide the strategic DRY / shared-knowledge strategy: monorepo, shared domain lib, custom platform / util lib — AND explicitly when NOT to share. Keep domain concepts OUT of generic/shared/infra layers (a shared layer coupled to one consumer's domain is no longer reusable). | Step 9 arch-rules + scaffold foundation |
| Dependency-boundary enforcement | Decide explicit dependency directions between modules/contexts and the mechanism that enforces them (no circular deps). | Step 9 "Arch rules / fitness" handoff → linter-setup |
These inputs are graded at init/audit by architecture-scalability-review; per-change regressions are caught by architecture-review. Do NOT turn this step into an auditor — record decisions here and route grading to those skills.
Step 3: Backend Architecture
3A: Architecture Styles
WebSearch top 3 backend architecture styles. Candidates:
| Style | Best For | Research Focus |
|---|---|---|
| Clean Architecture | Complex domains, long-lived projects | Dependency rule, testability, flexibility |
| Hexagonal (Ports+Adapt) | Integration-heavy, multiple I/O adapters | Port contracts, adapter isolation |
| Vertical Slice | Feature-focused teams, rapid delivery | Slice isolation, code locality |
| Modular Monolith | Starting simple, eventual decomposition | Module boundaries, migration path |
| Microservices | Large teams, independent deployment | Service boundaries, operational overhead |
| CQRS + Event Sourcing | Audit-heavy, complex queries | Read/write separation, event store |
| Layered (N-Tier) | Simple CRUD, small teams | Layer responsibilities, coupling risk |
Full 16-style matrix with per-style buys / costs / choose-when / avoid-when → .claude/docs/architecture-knowledge.md §5.
Style selection procedure (MANDATORY order — never shortcut)
- Take the ≤3 quantified driving attributes from Step 2-1.
- ELIMINATE every style that cannot meet them (state which attribute eliminated it).
- DESIGN IT TWICE — produce ≥2 MATERIALLY different surviving candidate designs (not two spellings of one idea) and write what each SACRIFICES. — why: committing to the first idea that occurred to you is the most common architecture failure and the one nobody records; a second real candidate is what makes the first one a choice.
- Among survivors take the SIMPLEST — not the most capable.
- Emit an ADR (Step 11) naming the rejected alternative AND the measurable trigger that would revisit the choice.
MANDATORY IMPORTANT MUST ATTENTION design-it-twice applies to EVERY one-way door from 2-0, not only the style choice — data model, tenancy model, consistency model per read path, sync-vs-async at a boundary. NEVER emit a one-way-door ADR whose "Alternatives considered" section was written to justify a decision already made. — why: a retrofitted alternative is advocacy, not evaluation, and it hides the sacrifice the reviewer needs to see.
Styles COMPOSE — modular monolith + event-driven integration + 2-3 extracted services is the most common good real answer. Recommending a single pure style is usually a sign step 2 was skipped.
MANDATORY IMPORTANT MUST ATTENTION — modulith-first default. Default to a modular monolith with CI-ENFORCED module boundaries (architecture tests, Step 9) and extract services ONLY against a named, measured trigger from the table below. Microservices are a destination reached under pressure, NEVER a starting point — the 2025-2026 industry correction is documented: many organizations re-consolidated after debugging complexity, ops overhead and network latency outweighed autonomy gains. — why: distribution bought speculatively pays every distributed cost immediately and collects the benefit never.
| Legitimate extraction trigger (record BEFORE building) | NOT a trigger (reject these) |
|---|---|
| Independent scaling profile ≥10x divergent | "The codebase feels big" |
| Different compliance / data-residency boundary | "Microservices are best practice" |
| Different availability requirement | A resume, a conference talk, or framework support |
| A team boundary PROVABLY blocked by shared deploys | One slow endpoint (fix the endpoint) |
| Genuinely different runtime need (GPU, language, memory profile) | A new team was hired |
| Fault isolation for a KNOWN-unreliable dependency | The domain has many entities |
MUST ATTENTION verify platform maturity before recommending microservices: CI/CD, IaC, distributed tracing, on-call, and a platform team. Microservices without them is the most reliable predictor of a failed migration — recommend the modulith and say so explicitly.
MUST ATTENTION draw boundaries around capabilities/behaviors (Checkout, Fulfilment, Pricing), NEVER around nouns/data (UserService, ProductService). Entity-per-service guarantees every real use case must synchronously traverse many services — a distributed monolith produced by design. The unit of extraction is the bounded context, not the entity.
3B: Backend Design Patterns
Evaluate applicability per layer:
| Pattern | Layer | When to Apply |
|---|---|---|
| Repository | Data Access | Abstract data store, enable testing |
| CQRS | Application | Separate read/write models, complex queries |
| Mediator | Application | Decouple handlers from controllers |
| Strategy | Domain/App | Multiple interchangeable algorithms |
| Observer/Events | Domain | Cross-aggregate side effects |
| Factory | Domain | Complex object creation with invariants |
| Decorator | Cross-cutting | Add behavior without modifying (logging, caching) |
| Adapter | Infrastructure | Isolate external dependencies |
| Specification | Domain | Composable business rules, complex filtering |
| Unit of Work | Data Access | Transaction management across repositories |
| Saga/Orchestr. | Cross-service | Distributed transactions, compensating actions |
| Outbox | Messaging | Reliable event publishing with DB transactions |
| Circuit Breaker | Infrastructure | External service resilience |
Per recommended pattern document: Apply to, Why, Example, Risk if skipped.
MUST ATTENTION patterns are a VOCABULARY for a solution you already need, never a menu to shop from — applying patterns to demonstrate knowledge produces the gas factory anti-pattern. The right number of patterns is the SMALLEST number that removes a DEMONSTRATED pain. Watch the chronically over-applied ones: Singleton (global mutable state → prefer one DI registration), Service Locator (hides dependencies from compiler and tests), CQRS on simple CRUD, event sourcing used as an audit log (an audit table is the right answer).
Purpose-oriented abstraction naming gate: Name ports, interfaces, modules, APIs, and adapters by the capability or domain contract consumers rely on; keep provider, SDK, framework, database, and transport details on concrete implementations (IStorage/Storage → AzureBlobStorage). Check the proposed name against callers and all implementations, use a narrower name when the contract is narrower, preserve local interface syntax, and require an evidenced boundary/substitution need before adding an abstraction.
Step 3C: Data & Consistency Architecture
Skip if: the change touches no persistence, no consistency boundary, and no tenant-scoped data. Otherwise MANDATORY.
Data outlives every service, framework and team — this is the MOST irreversible step in this skill. Treat every row below as a one-way door (Step 2-0) until proven otherwise: each needs an ADR and a Step-12 validation question.
| Decision | Decide + record | Failure if skipped |
|---|---|---|
| Store per access pattern | Pick each store from the ACCESS PATTERN, not familiarity: relational (relations/transactions/ad-hoc queries — the correct default) · document (aggregate-shaped reads) · key-value (lookup/session) · wide-column (huge writes, known queries) · graph (traversal) · time-series (append + rollups) · search (relevance/facets) · vector (semantic/ANN) · columnar (aggregation scans) · object storage (blobs). Each ADDITIONAL store needs its own justification — polyglot persistence costs per store (ops, backup, monitoring, expertise, and transactional impossibility across stores). | Golden-hammer: the wrong store makes the dominant query permanently expensive |
| One writer per dataset | Name the single owning module/service for every dataset. Many READERS are fine — via API, replica, or published event stream. | Shared write access is shared coupling with NO contract; data diverges and nobody owns correctness |
| NEVER integrate through the database | External consumers get an API, an event stream, or at most a published view/replica — never your tables. | Fastest known path to a distributed monolith and to "we can never change this table" |
| Consistency model per read path | Per read path choose strong / causal / session guarantees (read-your-writes, monotonic reads) / eventual — and write the STALENESS BUDGET ("search index may lag ≤5 s") as a monitored SLI (Step 8). | Unbounded, unmeasured lag IS the defect. Most user-visible "consistency bugs" are missing read-your-writes from a lagging replica, NOT missing linearizability |
| Replication + failover semantics | Name topology (single-primary/read replicas, quorum, or multi-primary), write acknowledgement, sync vs async replicas, failover authority, conflict policy, and RPO/RTO. Route lag-sensitive/read-after-write reads to the primary or use a version/sticky-read guarantee. | Replicas improve read capacity/availability, not write capacity; async failover can lose acknowledged writes, sync raises latency/lowers availability, multi-primary creates conflicts |
| Isolation level + check-then-act protection | NAME the isolation level per critical write path — "we use transactions" says nothing about correctness. Read Committed permits write skew AND lost update; snapshot isolation permits write skew and — on any engine whose REPEATABLE READ is not true first-committer-wins SI — lost update too, so name the ENGINE as well as the level and protect every check-then-act invariant one of FOUR deliberate ways: a DB constraint (unique/check/exclusion — cheapest and most durable) · SELECT … FOR UPDATE on the rows read · Serializable + an app-side retry loop for serialization failures · a single atomic conditional write (UPDATE … WHERE version = n). An invariant spanning rows that DO NOT YET EXIST (no double-booking, no overlapping shift, at most N per tenant) cannot be protected by row locks. Full anomaly table → .claude/docs/architecture-knowledge.md §8. |
Two concurrent transactions both pass their check and both write — the classic on-call corruption bug that passes every single-user test |
| Storage engine + index strategy | Choose B-Tree (mixed read/write, ad-hoc queries, strong secondary indexes) vs LSM (write-heavy ingest with known query shapes — pay with compaction stalls in p99 and space amplification). Record the WAL/fsync policy as the durability↔latency knob the RPO depends on. Index rules: composite indexes obey the leftmost-prefix rule ((a,b,c) never serves b alone) · covering indexes remove the row fetch · every index slows writes, so index-per-query-shape has a ceiling · size the connection pool by Little's Law. |
An unpooled service DOSes its own database; a wrong engine makes the dominant workload permanently expensive; fsync settings chosen by default silently violate the stated RPO |
| Storage substrate | Block storage for database/filesystem volumes needing low-latency random I/O · object storage for blobs/media/backups/log archives and cheap durable scale · shared file storage only when filesystem semantics are required. Record lifecycle tiering, access frequency, object size, durability, egress and mutation pattern. | "User data uses block storage" confuses application model with physical substrate; large immutable blobs in the transactional database inflate backup, replication and query costs |
| Distributed lock / leader election — fencing | If any flow takes a distributed lock or elects a leader, name the fencing token (monotonic, rejected by the storage layer when stale), the lease duration, and the behaviour when the lease expires mid-operation. Consensus (Raft/Paxos) needs a MAJORITY — a 2-node or even-sized cluster buys nothing — and stays OFF the hot path. NEVER order distributed events, compute expiry, or resolve conflicts by wall clock — use versions/sequences, logical/vector clocks, or HLC. | An unfenced lock fails exactly once — under a GC/VM pause, at peak, writing corrupted state — and looks correct in every test (split brain) |
| Transaction / aggregate boundary | One aggregate per transaction; reference other aggregates by ID only; keep aggregates SMALL; cross-aggregate consistency is EVENTUAL via domain events. Money movement, uniqueness, inventory decrement and auth state stay strong inside ONE aggregate/DB transaction. | Large aggregates cause lock contention; cross-aggregate transactions force 2PC or silent divergence |
| Cross-boundary transaction mechanism | Local ACID (ALWAYS prefer) → saga + compensation → reservation/TCC. AVOID 2PC/XA in web-scale distributed systems. Compensations are NEW BUSINESS FACTS (RefundIssued), not technical rollbacks — design them as product decisions, and design for the intermediate state being USER-VISIBLE. |
"We'll use a distributed transaction" is a non-answer that blocks on coordinator failure |
| Tenancy model | Shared-schema tenant_id (default for most B2B SaaS) · schema-per-tenant · DB-per-tenant (regulated / residency / white-label / large enterprise) · hybrid tiering (pooled small + siloed whales — the mature scale-up shape). |
Retrofitting tenancy is a full data migration |
| Tenant isolation ENFORCEMENT | In a pooled model, name the LOWEST-layer mechanism: database row-level security, an ORM global filter/interceptor, or a mandatory repository base injecting tenant from the authenticated principal — plus a test asserting cross-tenant reads return zero rows (Step 6 + Step 9 fitness rule). NEVER take tenant_id from a client-supplied field. |
One missing WHERE tenant_id = ? is a cross-tenant breach that passes every functional test |
| Keys & partitioning | Prefer time-ordered IDs (UUIDv7/ULID/Snowflake) — sequential ints leak volume and are enumerable; UUIDv4 destroys index locality on write. NEVER expose an internal sequential PK publicly. Partition key must be uniformly distributed AND query-aligned; plan resharding (consistent hashing / virtual buckets) BEFORE needing it. | Hot partitions (time-based ⇒ hot latest; tenant-based ⇒ whale tenants) and write amplification |
| OLTP / OLAP separation | Analytics go to a replica, CDC, or warehouse — never the transactional primary. | Reports saturating production is a top incident cause |
| Denormalization / caching as a PURCHASE | For each copy/cache, name authoritative source · policy (cache-aside/read-through/write-through/write-behind/refresh-ahead) · invalidation (TTL+jitter/event/versioned key/purge) · consistency window · max size/eviction. Design stampede/hot-key/cold-start protection (single-flight, early refresh, warm-up, LB slow-start). NEVER cache authorization decisions or tenant data under a key omitting identity/tenant/permission. | Stale data, stampedes and hot keys move rather than remove load; cache-key omission leaks tenants; an unbounded cache OOMs; a system correct only while cache is warm has made an undocumented source of truth |
| Migration strategy | Expand–contract (add nullable → dual write → backfill → switch reads → stop writing old → drop), forward-only, idempotent, non-blocking on large tables, deployable independently of the code using it. | A breaking migration in one deploy breaks old pods during a rolling deploy and makes rollback impossible |
| Lifecycle: classification, retention, residency, deletion | Classify (PII/PHI/PCI/public), set retention + archival tiering + deletion (GDPR/CCPA erasure) + residency NOW. | Retrofitting deletion into an event-sourced or heavily-denormalized system is brutally expensive — and erasure conflicts with immutable event stores by design |
| RPO / RTO per dataset | Set them PER DATASET (they drive topology and cost) and schedule a restore drill. | "We have backups" is a hypothesis; an undrilled DR plan has an RTO of "unknown" |
MANDATORY IMPORTANT MUST ATTENTION emit an ADR for the store choice, the tenancy model, the consistency model per read path, and the key strategy — these four are the least reversible decisions in the entire design — why: each one reversed later is a full data migration with downtime, not a refactor.
Step 3D: Integration & API Architecture
Skip if: no boundary is crossed — no external consumer, no second service, no message bus, no third-party integration. Otherwise MANDATORY.
| Decision | Decide + record | Failure if skipped |
|---|---|---|
| Sync vs async per boundary | Synchronous only when the caller genuinely cannot proceed without the answer (user-awaited QUERIES). Asynchronous for EFFECTS (notification, fan-out, work completable later). A sync chain deeper than 2-3 hops is an availability + latency defect — flatten, cache, or make it an event. | Sync chains MULTIPLY availability (five 99.9% deps ⇒ 99.5%) and SUM latency |
| Async acceptance contract | When work moves behind a queue, define the public state machine: accepted (202/job ID) → pending/running/succeeded/failed/cancelled; status lookup or callback; retry visibility; terminal failure ownership. User feedback MUST say accepted, not completed. |
Fast acknowledgement without completion semantics creates false success, invisible backlog, and unrecoverable business ambiguity |
| API style per consumer | REST/HTTP+JSON (public, broad compat, HTTP caching) · GraphQL (client-driven queries, aggregation — needs depth/complexity limits + persisted queries + dataloader or it becomes a DoS and N+1 surface) · gRPC (low-latency internal, streaming, codegen) · webhooks (push to third parties — needs retries + signature verification) · WebSocket/SSE (real-time; SSE when one-way suffices). | Wrong style makes the dominant interaction chatty or uncacheable |
| Versioning + deprecation policy | Version from day one (URL path versioning is the pragmatic default); version the CONTRACT, not every field; support ≥N-1 with a published deprecation policy + per-version usage telemetry. | Versionless contracts mean any producer change breaks consumers — and you cannot tell who |
| Contract-first + contract tests in CI | OpenAPI / protobuf / AsyncAPI as the source of truth; consumer-driven contract tests are what make independent deploys SAFE (Step 6 + Step 9 gate). Tolerant reader — unknown fields ignored, never fatal. | Without contract tests, "independently deployable" is an aspiration, not a property |
| Write-then-publish ⇒ transactional outbox or CDC | MANDATORY whenever a flow writes the DB and publishes. NEVER two independent operations. | Dual-write: DB commits + publish fails ⇒ silent divergence; publish succeeds + DB rolls back ⇒ phantom downstream data |
| Idempotency everywhere | Exactly-once DELIVERY is impossible (Two Generals/FLP) ⇒ effectively-once via idempotency. Idempotency keys (with the stored RESULT + TTL) on all unsafe mutations; consumers dedup on message ID; prefer naturally idempotent operations (SET status='paid' over balance += x); optimistic concurrency via version/ETag. Assume duplicate, out-of-order and delayed arrival — carry a version/sequence and discard backward transitions. |
Duplicate side effects: double charge, double email, double shipment |
| Message taxonomy — never conflate | Command ("do this", one handler, may be rejected) vs Event/fact ("this happened", 0..N subscribers, cannot be rejected) vs query vs document message. An "event" with exactly one permitted consumer that MUST handle it, whose failure means the flow failed, is a COMMAND in an event costume — name it a command and own the coupling honestly. | You pay async debugging difficulty AND keep sync coupling |
| Event granularity per stream | Deliberate choice: thin/notification (ID only — restores temporal coupling + read load) vs fat/state-transfer (self-contained, leaks more model, bigger payloads) vs hybrid (thin event + queryable snapshot endpoint). NEVER leak raw DB rows as events — CDC without a mapping layer publishes your internal schema as a frozen public contract (Hyrum). | Consumers become coupled to columns you can then never rename |
| Schema evolution | Versioned, registered, backward-compatible event schemas with a CI compatibility check. In event sourcing, event schemas are public contracts forever. | One producer change silently breaks every consumer |
| Broker semantics — ordering, replay, durability | Decide the three properties BEFORE naming a vendor: required ordering scope (global / per-entity-key / none) · required replay window (queue = consume-and-gone; log = offset-based replay by many consumer groups) · durability acknowledgement (replication factor + min-in-sync-replicas + producer acks — acks=1 accepts data loss on leader failure, and acks=all waits for the replicas CURRENTLY in the ISR — so min.insync=1 still waits for a healthy 3-replica ISR but silently degrades to acks=1 durability once the ISR shrinks to the leader alone). Log partition count is hard to raise without rekeying, and ordering on a key costs parallelism on that key. Health SLI: queue depth + oldest-message age, or consumer lag for a log. |
Vendor picked first ⇒ the one property you actually needed (ordering, replay, or durability) turns out to be the one that is expensive to change |
| Load-balancing + rate-limiting algorithm | LB: least-outstanding-requests is the best general default (routes away from slow hosts automatically) · power-of-two-choices · consistent hashing only for cache/shard affinity (accept hot keys) · slow-start for new instances so a cold cache/JIT node is not handed full traffic. Rate limiting: token bucket for burst-tolerant public APIs · sliding-window counter for accuracy · concurrency/in-flight limiter when per-request cost is unknown or highly variable (it bounds the resource, not the count). Limit BY the protected dimension (tenant/principal/endpoint), never only by IP; always return Retry-After. Distributed enforcement needs a shared counter (new hot-path dependency) or per-node quota division (accept N× slack) — state which. |
Round-robin ignores request cost and feeds a dying host; fixed-window limiters permit a 2× burst across the boundary; sticky sessions become the reason state was never externalized |
| Queue hygiene | Bounded queues + DLQ + a redrive procedure + DLQ-depth alerting; capped exponential backoff with jitter; poison-message handling. | An unbounded queue converts a throughput problem into unbounded latency then OOM; a DLQ nobody watches is data loss with extra steps; unjittered retries synchronize into a thundering herd |
| Resilience config on EVERY outbound call | Timeout (derived from the caller's remaining budget) on every network call, lock and query · capped jittered retries for idempotent ops ONLY · retry BUDGET as a % of traffic · circuit breaker with a defined fallback · bulkheads per dependency/tenant · load shedding at the edge by priority. | A missing timeout is the single most common resilience defect; retry amplification turns a blip into an outage. The dangerous failure is SLOW, not down — it exhausts your resources while looking healthy |
| Graceful degradation per feature | Pre-decide the degraded mode per feature (stale data / hide module / read-only) — a PRODUCT decision, made now, not during the incident. | Undesigned degradation becomes a total outage |
| Trust boundary rules | Validate at the boundary (allow-list); NEVER trust client-supplied authorization data — IDs, roles, prices, tenant IDs come from the authenticated principal. Machine-readable error contract (stable code, message, details, traceId; RFC 9457 problem+json is a good default) — NEVER leak stack traces. Propagate a correlation/trace ID through EVERY hop including async. |
Broken access control is the #1 real-world risk; untraceable async hops make incidents unexplainable |
| Edge component responsibilities | Gateway = TLS, routing, authn, rate limiting, quotas, versioning — NEVER business logic. CDN/edge = static + deliberately cacheable dynamic content; record push/pull origin strategy, Cache-Control, Vary/cache-key dimensions, TTL and purge/versioning. BFF only when a client genuinely needs owned aggregation; skip with one client or when GraphQL fills the role. |
Smart gateways duplicate domain rules; careless edge caching serves stale or personalized data to the wrong audience; missing cache policy shifts global latency/load back to origin |
MANDATORY IMPORTANT MUST ATTENTION every sync-vs-async choice at a boundary and every public API/event contract is a one-way door — ADR + Step-12 validation, no exceptions — why: consumers you cannot see will depend on both, and Hyrum's Law makes every observable behavior a contract you must then keep.
Step 4: Frontend Architecture
4A: Architecture Styles
WebSearch top 3 frontend architecture styles. Candidates:
| Style | Best For | Research Focus |
|---|---|---|
| MVVM | Data-binding heavy, forms-over-data apps | ViewModel responsibility, two-way binding |
| MVC | Server-rendered, traditional web apps | Controller routing, view separation |
| Component Architecture | Configured SPA/component framework | Component isolation, props/events, reuse |
| Reactive Store (Redux) | Complex state, multi-component sync | Single source of truth, immutable state |
| Signal-based Reactivity | Fine-grained reactivity in frameworks that support signals | Granular updates without broad change detection |
| Micro Frontends | Multiple teams, independent deployment | Module federation, routing, shared state |
| Feature-based Modules | Large monolith SPA, lazy loading | Feature boundaries, route-level splitting |
| Server Components (RSC) | SEO, initial load performance | Server/client boundary, streaming |
4B: Frontend Design Patterns
| Pattern | Layer | When to Apply |
|---|---|---|
| Container/Presentational | Component | Separate logic from UI rendering |
| Reactive Store | State | Centralized state, cross-component communication |
| Facade Service | Service | Simplify complex API interactions |
| Adapter/Mapper | Data | Transform API response to view model |
| Observer (RxJS) | Async | Event streams, real-time data, debounce/throttle |
| Strategy (renderers) | UI | Conditional rendering strategies per entity type |
| Composite (components) | UI | Tree structures, recursive components |
| Command (undo/redo) | UX | Form wizards, canvas editors, undoable actions |
| Lazy Loading | Performance | Route/module-level code splitting |
| Virtual Scrolling | Performance | Large lists, infinite scroll |
Step 4B: UI System Architecture
Skip if: Backend-only project, no frontend component.
Research, recommend project design system architecture. Use ask the user directly for each decision.
4B-1: Styling Approach
WebSearch top 3 styling approaches for confirmed frontend framework:
| Approach | Best For | Research Focus |
|---|---|---|
| Utility-first (Tailwind CSS) | Rapid prototyping, design enforcement | JIT, custom config, design tokens |
| CSS Modules / Scoped CSS | Component isolation, no global conflicts | Naming, composition patterns |
| SCSS/SASS with BEM | Complex theming, token variables | BEM methodology, mixin libraries |
| CSS-in-JS | Dynamic styling, theme providers | Runtime perf, SSR support |
| CSS Custom Properties | Native theming, framework-agnostic | Browser support, fallback strategy |
4B-2: Design Token Strategy
| Decision | Options | Default |
|---|---|---|
| Token format | CSS custom properties / JSON / SCSS variables | CSS custom properties |
| Token categories | Color, spacing, typography, breakpoints, shadows, z-index | All |
| Token naming | Semantic (--color-primary) vs Functional (--btn-bg) |
Semantic first |
| Theming | Light/dark toggle / Multi-brand / Single theme | Single + dark mode |
4B-3: Component Library Strategy
| Decision | Options | Default |
|---|---|---|
| Library | Build custom / Headless (Radix, Headless UI) / Full kit (MUI, Ant, PrimeNG) | Based on team and timeline |
| Component tiers | Common → Domain-Shared → Page (per ui-wireframe-protocol) | Standard 3-tier |
| Documentation | Storybook / Docusaurus / In-code only | Based on team size |
4B-4: Responsive Strategy
| Decision | Options | Default | | ----------- | ---
Truncated - read the full file at https://github.com/duc01226/easy-claude/blob/e46c5f1a56e43f9a04e7704ede06824623450bf6/.agents/skills/architecture-design/SKILL.md.