| name | architecture-enforcer |
| description | Synthex architecture pattern enforcer. NEVER suggest Redux, Zustand, tRPC, GraphQL, Server Actions for mutations, or any pattern absent from this codebase. NEVER allow cross-layer imports (page importing from lib/ directly). ALWAYS enforce: Pages → Components → Hooks → lib/ → Database. All mutations go through API routes. Activate on ANY request to design architecture, review patterns, plan a new system, refactor, or assess structural decisions. |
| metadata | {"author":"synthex","version":"1.0","engine":"synthex-ai-agency","type":"capability-uplift-code","triggers":["architecture check","pattern audit","consistency check","codebase review","convention check","architecture","pattern","refactor","design system","layer","structure","new system"]} |
| context | fork |
Architecture Enforcer — Pattern Consistency Guard
Purpose
Enforces architectural patterns across the entire SYNTHEX codebase. Prevents
the pattern drift where each new coding session — human or AI — introduces
its own conventions, imports, and approaches instead of following established
patterns.
This is the difference between "vibe coding" and senior engineering:
a senior engineer knows the codebase conventions and follows them consistently.
This skill encodes those conventions as automated checks.
When to Use
Activate this skill when:
- Reviewing a PR with changes across multiple files
- After a bulk refactoring session
- Running a periodic architecture health check
- Onboarding to understand codebase conventions
- Before a major release to ensure consistency
- After AI-assisted coding sessions to verify pattern adherence
When NOT to Use
- For individual API route security (use
route-auditor)
- For infrastructure security posture (use
security-hardener)
- For database schema patterns (use
database-prisma)
- For UI component design (use
design)
Tech Stack Context
- Framework: Next.js 15 App Router
- Language: TypeScript 5.7 (strict mode)
- Styling: Tailwind CSS with dark theme (bg-gray-950, cyan accents)
- Icons: Barrel export from
@/components/icons (lucide-react re-exports)
- ORM: Prisma via
@/lib/prisma
- Auth: Centralised in
@/lib/auth/jwt-utils
- Security:
@/lib/security/api-security-checker
- Multi-business:
@/lib/multi-business/business-scope
Pattern Checks
P1: Auth Centralisation
Rule: All app/api/ routes import auth from @/lib/auth/jwt-utils or use APISecurityChecker. No route should define its own auth functions.
Check:
grep -rn "function getJWTSecret\|function getUserFromRequest\|function getTokenFromRequest\|function getUserId(" app/api/ --include="*.ts"
grep -rn "from 'jsonwebtoken'" app/api/ --include="*.ts"
Expected: 0 results for both.
Fix: Replace with imports from @/lib/auth/jwt-utils.
P2: No Duplicate Utilities
Rule: Utility functions should exist in exactly one location. Specifically:
getJWTSecret() — only in lib/auth/jwt-utils.ts
verifyToken() — only in lib/auth/jwt-utils.ts
prisma client — only in lib/prisma.ts
Check:
grep -rn "function getJWTSecret" app/ lib/ --include="*.ts" | grep -v "lib/auth/jwt-utils"
grep -rn "new PrismaClient" app/ lib/ --include="*.ts" | grep -v "lib/prisma"
Expected: 0 results.
P3: Icon Barrel Imports
Rule: All icon imports must come from @/components/icons, never directly from lucide-react.
Why: The barrel export ensures consistent icon naming and allows future icon library changes.
Check:
grep -rn "from 'lucide-react'" components/ app/ --include="*.tsx" --include="*.ts" | grep -v "components/icons"
Expected: 0 results (only components/icons.tsx imports from lucide-react).
Fix: Change import { Icon } from 'lucide-react' to import { Icon } from '@/components/icons'.
P4: Prisma Import Path
Rule: Always import Prisma from @/lib/prisma, never from @prisma/client directly.
Why: The centralised import configures logging, connection pooling, and error handling.
Check:
grep -rn "from '@prisma/client'" app/ --include="*.ts" | grep -v "import.*Prisma\b\|import type"
Expected: Only type imports (import { Prisma } from '@prisma/client' for types is acceptable).
Fix: Use import { prisma } from '@/lib/prisma' for the client instance.
P5: API Response Format
Rule: API routes return consistent JSON structure:
- Success:
{ data: ... } or { ...data } with 200/201 status
- Error:
{ error: 'message' } with appropriate 4xx/5xx status
- Never:
{ message: ... }, { result: ... }, { success: true, ... }
Check: Manual review — look for inconsistent response shapes in API routes.
P6: Dark Theme Tokens
Rule: Use Tailwind utility classes for theming. Avoid hardcoded hex colours.
Anti-patterns: bg-[#0f172a], text-[#06b6d4], border-[#1e293b]
Preferred: bg-gray-950, text-cyan-400, border-gray-800, bg-[#0f172a]/80 (opacity variants are acceptable)
Check:
grep -rn "bg-\[#\|text-\[#\|border-\[#" components/ app/ --include="*.tsx" | grep -v "/80\|/60\|/40\|/20\|/50"
Note: Opacity variants like bg-[#0f172a]/80 are acceptable as Tailwind doesn't support opacity on arbitrary colours natively.
P7: Client Directive
Rule: Every React component that uses hooks (useState, useEffect, useRef, etc.) or browser APIs must have 'use client' as the first line.
Check:
grep -rln "useState\|useEffect\|useRef\|useCallback\|useMemo\|useContext" components/ app/ --include="*.tsx" | xargs grep -L "'use client'"
Expected: 0 results.
P8: Fetch Credentials
Rule: All client-side fetch() calls must include credentials: 'include'.
Why: Without this, the httpOnly auth-token cookie is not sent, causing auth failures.
Check:
grep -rn "fetch(" components/ app/ hooks/ --include="*.tsx" --include="*.ts" | grep -v "credentials.*include\|server\|api/\|node_modules"
P9: Multi-Business Scoping
Rule: Routes that query data for the current user/organisation must use userId filtering or getEffectiveQueryFilter() from @/lib/multi-business/business-scope.
Why: Without org scoping, multi-business users could see data from wrong organisations.
Check: Manual review — look for Prisma queries in API routes that access user data without userId or organizationId in the where clause.
P10: Dead Code Detection
Rule: No unused imports, no unused variables, no large commented-out code blocks (>5 lines).
Check:
grep -rn "^[[:space:]]*//" app/ components/ lib/ --include="*.ts" --include="*.tsx" | head -50
Note: This check is best done by running ESLint with no-unused-vars and no-unused-imports.
Input Specification
| Parameter | Type | Required | Description |
|---|
| target | string | no | Directory or file to check (default: entire project) |
| scope | string | no | Specific pattern IDs: P1,P3,P7 or all (default: all) |
| fix | boolean | no | Auto-fix safe patterns (P3, P4, P7) where possible |
Output Specification
Output Format
## Architecture Consistency Report — SYNTHEX
### Pattern Violations Found
#### P1: Auth Centralisation [5 violations]
- app/api/analytics/reports/route.ts — defines local getJWTSecret() (line 12)
- app/api/auth/api-keys/route.ts — imports from 'jsonwebtoken' (line 3)
- app/api/auth/user/route.ts — defines local getUserFromRequest() (line 18)
- app/api/invoices/route.ts — defines local getJWTSecret() (line 8)
- app/api/notifications/stream/route.ts — defines local getJWTSecret() (line 10)
#### P3: Icon Barrel Imports [PASS]
No direct lucide-react imports found outside icons barrel.
#### P7: Client Directive [2 violations]
- components/business/BusinessSwitcher.tsx — uses useState but missing 'use client'
- app/dashboard/settings/page.tsx — uses useEffect but missing 'use client'
### Summary
- Patterns checked: 10
- Passed: 7
- Violations: 3 (P1: 5 files, P7: 2 files)
- Auto-fixable: 2 (P7)
Instructions
- Accept target — Default to full project scan if no target specified
- Run each pattern check using the provided grep commands
- Report violations with file paths and line numbers
- Group by pattern and count violations per pattern
- Suggest fixes with code snippets and reference to canonical implementations
- If
fix mode, auto-fix safe patterns (P3 icon imports, P4 Prisma imports, P7 client directive)
Error Handling
| Error | Action |
|---|
| No files found in target | Report: "No TypeScript files found in specified directory" |
| Grep returns no matches | Report pattern as PASS |
| File permission error | Skip and report |
Reference Files (Canonical Implementations)
lib/auth/jwt-utils.ts — Auth pattern (P1, P2)
components/icons.tsx — Icon barrel (P3)
lib/prisma.ts — Prisma client singleton (P4)
app/api/campaigns/route.ts — Reference API route (P5, P9)
middleware.ts — Security headers reference
Integration Points
- Complements route-auditor (route-specific vs codebase-wide)
- Complements security-hardener (architecture vs security)
- Called by senior-reviewer agent for comprehensive reviews
- Feeds into post-route-create hook for new route validation
Capability Uplift — Override Defaults
NEVER recommend architectural patterns not present in the Synthex codebase:
Redux, Zustand, tRPC, GraphQL, Server Actions for mutations, React Query.
Never allow cross-layer imports. Never suggest splitting the monorepo.
INSTEAD every architectural decision must:
- Trace back to an existing pattern in the codebase (find it with Grep first)
- Follow the layer rule:
app/ pages → components/ → hooks/ → lib/ → Prisma → DB
- Route all mutations through
app/api/ routes with Zod validation
- Use SWR for client-side data (never useEffect + fetch)
- Keep auth in
lib/auth/ — never duplicate auth logic in components
New patterns require: existing pattern was insufficient + migration path documented.
REFERENCE .claude/skills/synthex-standards/references/code-standards.md
Commands
echo "=== P1: Auth Centralisation ===" && \
grep -rn "function getJWTSecret\|from 'jsonwebtoken'" app/api/ --include="*.ts" | grep -v "lib/auth" | wc -l && \
echo "=== P3: Icon Barrel ===" && \
grep -rn "from 'lucide-react'" components/ app/ --include="*.tsx" | grep -v "components/icons" | wc -l && \
echo "=== P4: Prisma Import ===" && \
grep -rn "from '@prisma/client'" app/ --include="*.ts" | grep -v "import.*type\|import type" | wc -l && \
echo "=== P7: Client Directive ===" && \
grep -rln "useState\|useEffect" components/ app/ --include="*.tsx" | xargs grep -L "'use client'" 2>/dev/null | wc -l
Review Board Output
When invoked as part of the Synthex Review Board pipeline, produce output matching the schema in .claude/skills/review-board/_shared/output-schema.md.
Map this skill's findings to the shared format:
specialist: Use this skill's name from frontmatter
severity: Map findings to CRITICAL/HIGH/MEDIUM/LOW per .claude/skills/review-board/_shared/severity-levels.md
confidence: Assign 0-100 based on certainty. Only findings >= 80 are shown to the developer.
verdict: BLOCK if any CRITICAL finding exists, otherwise PASS
- Include
file, line, issue, fix, and optional reference for each finding
- If no findings, return empty findings array with verdict PASS