Architecture pattern selection, folder structures, coding conventions, error handling, testing strategies, and platform-specific patterns for structuring application code
Application Patterns
Authoritative reference for selecting and applying the application_patterns manifest block during blueprint generation. Covers architecture pattern selection, folder structures, coding conventions, error handling, testing strategies, and platform-specific patterns.
For security architecture (auth, OWASP, API security), see operational-patterns. For infrastructure and tooling decisions (cloud, database, hosting), see prescriptive-decision-framework.
Architecture Pattern Selection
Decision Inputs
Input
How to Determine
Team size
Gating question 5 or tech constraints section
Domain complexity
Simple CRUD (< 10 entities) vs complex business rules vs event-heavy workflows
Deployment model
Single deployable vs multiple services (from scale/team gating)
Platform
Backend API, frontend web app, mobile app, or full-stack
Architecture Pattern Decision Tree
IF simple CRUD app with < 10 entities AND team <= 3:
-> RECOMMEND: layered
-> REASONING: "Simplest to build and hire for. Controllers -> services -> data access. No abstraction overhead."
-> ALTERNATIVE: "mvc if server-rendered pages are needed (admin panels, forms)"
-> DON'T USE: "clean-architecture or hexagonal — overkill for simple CRUD"
ELSE IF server-rendered pages with forms (admin panels, CRM, dashboards):
-> RECOMMEND: mvc
-> REASONING: "Natural fit for request/response with views. Well-understood by most developers."
-> ALTERNATIVE: "layered if API-only with separate frontend"
-> DON'T USE: "cqrs, event-driven — wrong paradigm for form-based apps"
ELSE IF mobile or reactive UI with data-binding (React Native, Flutter):
-> RECOMMEND: mvvm
-> REASONING: "ViewModel decouples business logic from UI. Natural fit for reactive/declarative frameworks."
-> ALTERNATIVE: "clean-architecture if domain logic is complex beyond UI state"
-> DON'T USE: "mvc — poor fit for reactive/declarative UI frameworks"
ELSE IF complex business logic with many domain rules AND high testability needed:
-> RECOMMEND: clean-architecture
-> REASONING: "Domain at center, dependencies point inward. Business logic testable without framework/DB. Best for long-lived codebases."
-> ALTERNATIVE: "hexagonal if swappable external integrations matter more than layered use-case organization"
-> DON'T USE: "For MVPs or simple CRUD — the abstraction overhead slows early development"
ELSE IF many external integrations that may change (payment providers, notification services, AI providers):
-> RECOMMEND: hexagonal
-> REASONING: "Ports and adapters. Swap Stripe for Adyen, swap OpenAI for Anthropic — without touching business logic."
-> ALTERNATIVE: "clean-architecture if the domain rules are more complex than the integration surface"
ELSE IF single deployable AND team 3-10 AND multiple bounded contexts:
-> RECOMMEND: modular-monolith
-> REASONING: "Module isolation without deployment complexity. Each module owns its data/logic. Can extract to microservices later."
-> ALTERNATIVE: "clean-architecture if there's one dominant domain, not multiple contexts"
-> DON'T USE: "microservices — same organizational benefit, 5x more operational complexity at this team size"
ELSE IF team > 10 backend engineers AND services need independent deployment and scaling:
-> RECOMMEND: microservices
-> REASONING: "Independent deploys, independent scaling, independent tech choices per service. Required at this team size for velocity."
-> DON'T USE: "At MVP stage or with < 5 engineers — operational overhead destroys velocity"
ELSE IF low-traffic bursty workloads AND no persistent connections:
-> RECOMMEND: serverless
-> REASONING: "Pay per invocation. Auto-scales to zero. Ideal for webhooks, cron jobs, event processors."
-> ALTERNATIVE: "layered on Railway/Render if you need persistent connections (WebSockets)"
-> DON'T USE: "For real-time features, long-running jobs, or latency-sensitive APIs (cold starts)"
ELSE IF components react to events asynchronously (order placed -> email + inventory + analytics):
-> RECOMMEND: event-driven
-> REASONING: "Decouples producers from consumers. New consumers don't require changes to producers. Natural for async workflows."
-> ALTERNATIVE: "cqrs if read/write asymmetry is the primary concern rather than event flow"
-> DON'T USE: "Simple request/response CRUD — adds unnecessary complexity"
ELSE IF read and write patterns are fundamentally different (high-read dashboards + low-write mutations):
-> RECOMMEND: cqrs
-> REASONING: "Separate read models (optimized for queries) from write models (optimized for business rules). Scale reads independently."
-> ALTERNATIVE: "event-driven if the asymmetry is about workflow rather than read/write patterns"
-> DON'T USE: "Simple CRUD where reads and writes use the same model"
ELSE (default):
-> RECOMMEND: layered
-> REASONING: "Safe default. Easiest to hire for. Can evolve to modular-monolith or clean-architecture when complexity justifies it."
Within module: any direction. Cross-module: public API (index.ts) only
Module A importing Module B's internal service
mvc
views -> controllers -> models (never reverse)
Model importing view logic
mvvm
view -> viewmodel -> model (never reverse)
Model importing view state
Error Handling Patterns
Application-level error handling for structuring, propagating, and responding to errors. For security error mitigations (OWASP, rate limiting, input sanitization), see operational-patterns.
Standard Error Response Shape
interfaceAppError {
code: string; // Machine-readable: "ORDER_NOT_FOUND", "VALIDATION_FAILED"message: string; // Human-readable: "Order not found"details?: unknown; // Validation errors array, debug contextrequestId: string; // For support correlation
}
Error Handling Strategy by Pattern
Pattern
Strategy
Implementation
layered / mvc
Try-catch in controllers, centralized error middleware
Express app.use((err, req, res, next) => ...) catches all
clean-architecture
Domain errors as typed classes, use-case catches and maps to application errors
Each service returns domain error codes, API gateway maps to HTTP
gRPC status codes -> HTTP status codes at gateway
Domain Error to HTTP Status Mapping
Domain Error Type
HTTP Status
When
ValidationError
400
Input fails schema or business rule validation
AuthenticationError
401
Missing, expired, or invalid credentials
ForbiddenError
403
Valid auth but insufficient permissions
NotFoundError
404
Entity does not exist or is not accessible
ConflictError
409
Duplicate resource, idempotency key collision
RateLimitError
429
Too many requests
ExternalServiceError
502
Upstream dependency failed
UnexpectedError
500
Unhandled exception (log full stack, return generic message)
Error Propagation Rules
Never expose stack traces or internal error details in production responses
Log the full error server-side (with requestId), return sanitized AppError to the client
Distinguish client errors (4xx — don't retry) from server errors (5xx — may retry with backoff)
Use requestId for cross-service correlation. See operational-patterns structured logging for format.
For async errors, route to dead letter queue. See architecture-methodology invariant on at-least-once processing with DLQ.
Frontend: use error boundaries (React) or global error handlers to catch rendering errors without crashing the app
Testing Strategy Patterns
Testing Pyramid by Architecture Pattern
Pattern
Unit Tests
Integration Tests
E2E Tests
Contract Tests
Ratio
layered / mvc
Service logic, validators
API endpoints (supertest)
Critical user flows
N/A
70 / 20 / 10
clean-architecture
Use cases, domain entities
Adapters against real DB
Critical user flows
N/A
60 / 30 / 10
modular-monolith
Per-module service logic
Per-module API + cross-module
Critical cross-module flows
Between modules
50 / 25 / 10 / 15
microservices
Per-service logic
Intra-service with test DB
Cross-service critical paths
Between services (Pact)
50 / 20 / 10 / 20
event-driven
Event handlers, validators
Event processing pipeline
End-to-end event flows
Event schema validation
50 / 20 / 10 / 20
serverless
Function logic
With local emulator (SAM)
Deployed endpoint smoke tests
N/A
60 / 30 / 10
What to Test Where
Layer
What to Test
What NOT to Test
Tooling
Domain / business logic
Rules, calculations, state transitions, edge cases
Framework code, database queries
Jest, Vitest, pytest
API endpoints
Request/response contracts, auth, validation, status codes
Internal service implementation
Supertest, httpx, Playwright API
Database
Migrations, complex queries, indexes, constraints
Simple CRUD operations
Testcontainers, in-memory SQLite
External integrations
Contract compliance, error handling for failures
Third-party uptime or correctness
MSW (mocks), Pact (contracts)
Frontend components
User interactions, conditional rendering, form validation
Styling, pixel-level layout
Testing Library, Storybook
E2E flows
Critical user journeys (signup, checkout, payment)
Every possible path
Playwright, Cypress
Testing Strategy Templates
Use these templates when populating the testing_strategy manifest field:
MVP / simple app:
Unit tests for business logic (Jest/Vitest). Integration tests for API endpoints (supertest). No E2E yet. Coverage target: 60%. Run in CI on every PR.
Multi-service production:
Unit tests for domain logic per service. Integration tests per service with test database. Contract tests between services (Pact). E2E for critical user flows (Playwright). Coverage target: 80%. Run in CI, E2E on staging deploy.
Event-driven / async:
Unit tests for event handlers and validators. Integration tests for event processing pipeline. Schema validation tests for event contracts. DLQ monitoring as implicit regression detection. Coverage target: 70%.
Frontend-Specific Patterns
State Management Selection
IF app has < 5 pages AND minimal shared state:
-> RECOMMEND: React useState + Context
-> REASONING: "No extra dependencies. Sufficient for simple apps. Upgrade when state gets complex."
-> DON'T USE: "Redux, Zustand — overkill at this scale"
ELSE IF primary state is server data (CRUD app, dashboard, admin panel):
-> RECOMMEND: React Query / TanStack Query (server state) + Zustand (client state)
-> REASONING: "Server cache is not client state. React Query handles caching, revalidation, loading states. Zustand for UI-only state (modals, sidebar)."
ELSE IF complex client-side state (collaborative editor, form builder, drag-and-drop):
-> RECOMMEND: Zustand or Redux Toolkit
-> REASONING: "Need predictable state updates, middleware, devtools, undo/redo support."
ELSE IF Next.js App Router with server components:
-> RECOMMEND: Server components for data fetching + Zustand for client state
-> REASONING: "Server components eliminate client state for read data. Zustand handles remaining interactive state."
ELSE IF Vue / Nuxt:
-> RECOMMEND: Pinia
-> REASONING: "Official Vue state management. Composable, typed, devtools integrated."
Drawer navigator with stack navigators per section
Deep-link driven (content apps, shared URLs)
URL-based file routing
Expo Router (file-based routing with deep link support)
Platform Abstraction Layer
Create a services/ directory with platform-agnostic interfaces for capabilities that differ across platforms:
Service
What It Abstracts
Example Implementations
storage.ts
Secure key-value storage
Expo SecureStore, MMKV, AsyncStorage
notifications.ts
Push notification registration and handling
Expo Notifications, Firebase Cloud Messaging
biometrics.ts
Biometric authentication
Expo LocalAuthentication
camera.ts
Camera and image capture
Expo Camera, react-native-image-picker
Same principle as hexagonal architecture ports/adapters: feature code depends on the interface, not the platform implementation. Swap implementations without changing feature code.
Choosing Patterns for a Blueprint
Quick-reference table for selecting the full application_patterns block based on project profile:
Project Profile
Architecture
Folder Convention
Error Handling
Testing Strategy
Simple CRUD API
layered
layer-based
Centralized error middleware + status code mapping
Unit + integration per module + cross-module contract
Event-driven system
event-driven
feature-based
DLQ + structured error events + retry with backoff
Handler unit + schema validation + pipeline integration
Serverless API
serverless
flat
Structured error responses per function
Function unit + emulator integration (60/40)
Mobile app
mvvm
feature-based
Error boundaries + retry on network failure
Component unit + integration + E2E critical flows
Full-stack Next.js
layered
feature-based
Server action errors + error.tsx boundaries + API error middleware
RSC + API + Playwright E2E
For security architecture decisions, see operational-patterns. For infrastructure and tooling decisions (cloud, database, auth, hosting), see prescriptive-decision-framework. For domain-specific depth (multi-tenant isolation, payment flows, AI orchestration), see product-type-detector templates. To evaluate your chosen patterns against quality standards, see well-architected.