ASAASA Standard
Active Phase 1Slice Architecture

ASA Architecture — Domain Slices & Boundaries

Architecture · ARCH-01, ARCH-02, ARCH-03, ARCH-04, ARCH-05, ARCH-06 · Priority: P0

Why It Matters

AI tools generate code without architectural awareness. Every prompt adds files wherever seems convenient — business logic in pages, shared utilities mixed with domain code, imports crossing boundaries freely. After 50-100 prompts, one change breaks three unrelated features because everything is connected to everything.

The ASA architecture pattern prevents this by enforcing clear boundaries: each feature lives in its own domain slice, pages are thin routing wrappers, and cross-domain coupling is blocked.

Priority: P0 — Without architecture enforcement, AI-generated code becomes unmaintainable. Each new prompt increases the probability of cascading failures.

Affected Stack: Next.js (App Router), React


ARCH-01 — Business logic in domains/

The Problem

AI tools put business logic wherever the current prompt lands — in page files, API routes, shared utilities, or root-level files. This makes the code impossible to reason about: where does billing logic live? Everywhere.

// ❌ Business logic scattered across the app
app/dashboard/page.tsx    → 200 LOC with API calls, state management, business rules
shared/utils.ts           → billing calculations mixed with string helpers
app/api/webhook/route.ts  → auth checks mixed with billing fulfillment

The Fix

All business logic belongs in src/domains/{feature}/:

// ✅ ASA architecture — business logic in domain slices
domains/
  billing/
    lib/checkout.ts        → checkout logic
    lib/webhook-handler.ts → webhook processing
    ui/PricingCard.tsx      → billing UI components
  auth/
    lib/session.ts         → session management
    lib/middleware.ts       → auth middleware

ARCH-02 — domains/ directory exists

The Problem

Without a domains/ directory, there is no designated place for business logic. Code spreads across lib/, utils/, helpers/, components/, and page files — with no convention to follow.

The Fix

Create src/domains/ as the single home for all business logic. Each domain gets its own subdirectory with lib/ for logic and ui/ for components.


ARCH-03 — No cross-domain imports

The Problem

When domains/billing/ imports from domains/auth/, changing auth can break billing. This invisible coupling is the root cause of "I changed one thing and broke everything."

// ❌ Cross-domain import creates hidden coupling
// In domains/billing/lib/checkout.ts
import { getSession } from '@/domains/auth/lib/session';

The Fix

Domains import only from shared/. If two domains need the same functionality, it lives in shared/:

// ✅ Both domains import from shared
// In domains/billing/lib/checkout.ts
import { getSession } from '@/shared/auth/session';

ARCH-04 — Thin pages (< 80 LOC)

The Problem

AI tools put everything into page files — data fetching, state management, business logic, UI rendering. A 300-line page file is a maintenance nightmare: changing any part risks breaking every other part.

The Fix

Pages are thin routing wrappers. Max 80 lines. They import from domains and compose — never implement:

// ✅ Thin page — routing + layout only
import { DashboardView } from '@/domains/dashboard/ui/DashboardView';

export default function DashboardPage() {
  return <DashboardView />;
}

ARCH-05 — shared/ has no business logic

The Problem

shared/ becomes a dumping ground for code that "doesn't belong anywhere." Over time, billing calculations, auth checks, and admin logic accumulate in shared/utils/ — creating a hidden dependency hub that couples everything.

The Fix

shared/ contains only cross-cutting infrastructure: database clients, type definitions, UI primitives, layout components. Any logic specific to billing, auth, or admin belongs in its domain slice.


ARCH-06 — File size limit (> 500 LOC)

The Problem

AI tools add code to the most convenient location — typically the file that already contains related logic. After 50-100 prompts, a single file grows to 500, 800, even 1000+ lines. At that point, the AI itself can't reason about the file anymore — it loses context, introduces contradictions, and breaks existing logic.

This is one of the primary causes of the "AI wall" — the point where the AI tool stops being able to make productive changes.

The Fix

Split oversized files into smaller, focused modules. Each file should have a single responsibility:

// ❌ Before: one 800-line god component
// domains/billing/checkout.ts (800 lines)
// - checkout logic
// - webhook handling
// - validation
// - email notifications

// ✅ After: four focused files
// domains/billing/checkout/handler.ts (~150 lines) — checkout flow
// domains/billing/webhook/handler.ts (~120 lines) — webhook processing
// domains/billing/checkout/schemas.ts (~60 lines) — validation
// domains/billing/checkout/notifications.ts (~80 lines) — emails

Hard limit: Files over 500 LOC fail the check. Aim for under 300 LOC per file.


Related Checks


Is your app safe? Run Free Scan →