--- name: Clarity DAL Architect description: Enforce Clarity project-specific architecture patterns - DAL for auth, type centralization in @/lib/types, repository pattern, balance helpers, and Drizzle ORM usage. Project-specific compliance checker. version: 1.0.0 --- # Clarity DAL Architect ## Overview Specialized skill for **Clarity project-specific** architecture patterns. Enforces: - **DAL (Data Access Layer)** - Centralized auth with `getUserId()`, `verifySession()` - **Type Centralization** - Domain types only in `@/lib/types` - **Repository Pattern** - Data access in `/lib/db/repositories` - **Balance Helpers** - Encryption-aware balance handling - **Drizzle Imports** - Operators from `drizzle-orm`, not `@/lib/db` ## When to Use Invoke when: - "Audit Clarity architecture" - "Check DAL usage" - "Fix auth patterns" - "Verify type imports" - "Review database access" - Working on Clarity-specific code ## Core Patterns ### 1. DAL for Authentication ```ts // ✅ CORRECT - Server Components use DAL import { getUserId, getUser, verifySession } from '@/lib/data/dal' // Simple auth check (auto-redirects to /sign-in) export default async function Page() { await verifySession() return } // Need user ID for queries export default async function Page() { const userId = await getUserId() // Auto-redirects if unauthenticated const data = await fetchData(userId) return } // Need full User object export default async function Page() { const user = await getUser() // Auto-redirects if unauthenticated return } // Optional auth (don't redirect) export default async function Page() { const session = await getSession() // Returns null if unauthenticated return session ? : } // ❌ WRONG - Direct Supabase auth import { createClient } from '@/lib/db/supabase/server' export default async function BadPage() { const supabase = await createClient() const { data: { user } } = await supabase.auth.getUser() // Don't do this! if (!user) redirect('/sign-in') } ``` ### 2. Type Centralization ```ts // ✅ CORRECT - Import from @/lib/types import type { Transaction, Account, User, Connection, Asset, Portfolio, Holding, } from '@/lib/types' export function TransactionList({ transactions }: { transactions: Transaction[] }) { return
    ...
} // ❌ WRONG - Local type definition export function BadTransactionList({ transactions, }: { transactions: Array<{ id: string amount: number date: string }> }) { // Duplicating Transaction type! } // ❌ WRONG - Importing from wrong location import type { Transaction } from '@/lib/transactions/types' // Should be: import type { Transaction } from '@/lib/types' ``` ### 3. Repository Pattern ```ts // ✅ CORRECT - Use repositories import * as AccountRepository from '@/lib/db/repositories/accounts' export async function getAccountData(userId: string) { const accounts = await AccountRepository.findByUserId(userId) return accounts } // ❌ DEPRECATED - Direct queries module import { accountQueries } from '@/lib/db/queries' const accounts = await accountQueries.getByUserId(userId) ``` ### 4. Balance Helpers ```ts // ✅ CORRECT - Use getAccountBalance helper import { getAccountBalance } from '@/lib/db/utils/balance-helpers' export async function processAccount(account: Account) { const balance = getAccountBalance( account.balance, account.metadata, encryptionKey, account.id ) // Helper has fallback to metadata if decryption fails return balance } // ❌ WRONG - Direct decryption (no fallback) import { decryptBalance } from '@/lib/encryption' export async function badProcessAccount(account: Account) { const balance = decryptBalance(account.balance, { key }) // Throws on failure! return balance } ``` ### 5. Drizzle ORM Imports ```ts // ✅ CORRECT - Import operators from drizzle-orm import { eq, and, or, gt, lt, isNull } from 'drizzle-orm' import { db } from '@/lib/db' import { accounts } from '@/lib/db/schema' const userAccounts = await db.query.accounts.findMany({ where: and( eq(accounts.userId, userId), gt(accounts.balance, 0) ), }) // ❌ WRONG - Importing from @/lib/db import { eq, and } from '@/lib/db' // Should be: import { eq, and } from 'drizzle-orm' ``` ### 6. Barrel Exports ```ts // ✅ CORRECT - Import from index.ts import { formatCurrency, formatDate } from '@/lib/utils' import { getUserAccounts } from '@/lib/services/accounts' // ❌ LESS IDEAL - Direct file imports (but acceptable) import { formatCurrency } from '@/lib/utils/formatters/format' import { getUserAccounts } from '@/lib/services/accounts/get-accounts' ``` ## Client-Side Auth ### 1. useAuthUser Hook (Recommended) ```tsx // ✅ CORRECT - Performance-optimized auth hook 'use client' import { useAuthUser } from '@/hooks/use-auth-user' export function ProfileSettings() { const { user, ready } = useAuthUser() if (!ready) return
Loading...
if (!user) return
Please sign in
return } ``` ### 2. useAuth Context (Alternative) ```tsx // ✅ ALTERNATIVE - Context-based auth 'use client' import { useAuth, useRequireAuth } from '@/lib/hooks/contexts/auth-context' export function UserProfile() { const { user, loading, signOut } = useAuth() if (loading) return
Loading...
if (!user) return
Not authenticated
return (

Welcome {user.email}

) } // Or require auth (redirects if not authenticated) export function ProtectedComponent() { useRequireAuth() return
Protected content
} ``` ## Architecture Layers ### Clarity's 3-Layer Type Architecture ``` ┌─────────────────────────────────────┐ │ Presentation Layer │ │ (components/, app/) │ │ - UI-specific types │ │ - FormData, display formats │ └─────────────────────────────────────┘ │ transforms ▼ ┌─────────────────────────────────────┐ │ Business Logic Layer │ │ (@/lib/types) ← CANONICAL │ │ - Domain types (Transaction, etc) │ │ - Business rules │ └─────────────────────────────────────┘ │ maps to ▼ ┌─────────────────────────────────────┐ │ Data Layer │ │ (@/lib/db/schema) │ │ - Database schema types │ │ - ORM-specific types │ └─────────────────────────────────────┘ ``` ### Type Import Rules ```ts // ✅ Domain types from @/lib/types import type { Transaction, Account } from '@/lib/types' // ✅ Schema types from @/lib/db/schema import type { transactions, accounts } from '@/lib/db/schema' // ✅ UI-specific types local to component type TransactionListProps = { transactions: Transaction[] onSelect: (id: string) => void } // ❌ WRONG - Domain type defined locally type Transaction = { id: string; amount: number } // Should import from @/lib/types ``` ## Audit System ### How to Audit **Invoke audit mode:** ``` Audit Clarity patterns in app/(auth)/dashboard/page.tsx ``` The skill checks: 1. **Auth**: Using DAL methods (not direct Supabase) 2. **Types**: Importing from `@/lib/types` (not local definitions) 3. **Data Access**: Using repositories (not direct queries) 4. **Balance Helpers**: Using `getAccountBalance` (not direct decryption) 5. **Drizzle Imports**: From `drizzle-orm` (not `@/lib/db`) ### Audit Report ```markdown ## Clarity Architecture Audit: app/(auth)/dashboard/page.tsx **Compliance Score**: 72/100 (Acceptable ⭐⭐⭐) ### ✅ Compliant Patterns - DAL usage for auth (getUserId) - Repository pattern for data access - Type imports from @/lib/types ### 🚨 Critical Violations #### 1. Direct Supabase Auth (Line 15) **Current**: ```ts const supabase = await createClient() const { data: { user } } = await supabase.auth.getUser() ``` **Fix**: Use DAL ```ts import { getUserId } from '@/lib/data/dal' const userId = await getUserId() ``` **Impact**: HIGH - Bypassing centralized auth layer #### 2. Local Type Definition (Line 25) **Current**: ```ts interface Transaction { id: string amount: number } ``` **Fix**: Import canonical type ```ts import type { Transaction } from '@/lib/types' ``` **Impact**: HIGH - Type duplication, inconsistent with codebase ### ⚠️ High Priority Issues #### 3. Wrong Drizzle Import (Line 40) **Current**: ```ts import { eq } from '@/lib/db' ``` **Fix**: Import from drizzle-orm ```ts import { eq } from 'drizzle-orm' ``` **Impact**: MEDIUM - Using deprecated export path ### Score Breakdown - Auth (DAL): 15/25 🚨 - Type Centralization: 15/25 🚨 - Data Access: 20/20 ✅ - Balance Helpers: 10/10 ✅ - Drizzle Imports: 12/20 ⚠️ ``` ### Scoring Rubric **Critical Violations (25 points each)**: - [ ] Using DAL for auth (not direct Supabase) - [ ] Types from `@/lib/types` (not local definitions) - [ ] Repository pattern (not direct queries) - [ ] No business logic in Server Components **High Priority (15 points each)**: - [ ] Balance helpers usage - [ ] Drizzle imports from `drizzle-orm` - [ ] Barrel exports used - [ ] Cache Components integration **Medium Priority (5 points each)**: - [ ] Consistent error handling - [ ] Proper type transformations - [ ] Service layer usage - [ ] Supabase client selection ## Project-Specific Conventions ### File Organization ``` /Users/zach/Documents/clarity/ ├── lib/ │ ├── types/ # ← CANONICAL domain types │ ├── data/ │ │ └── dal.ts # ← Auth functions │ ├── db/ │ │ ├── repositories/ # ← Data access │ │ ├── services/ # ← Business logic │ │ ├── schema/ # ← Drizzle schema │ │ └── utils/ │ │ └── balance-helpers.ts # ← Balance encryption │ ├── cache/ │ │ └── tags.ts # ← Cache tag constants │ └── utils/ │ ├── formatters/ │ └── kv.ts # ← Vercel KV wrapper └── app/ ├── (auth)/ # ← Protected routes ├── (public)/ # ← Public routes └── actions.ts # ← Server Actions ``` ### Cache Tags ```ts // lib/cache/tags.ts export const UserTags = { accounts: (userId: string) => `user:${userId}:accounts`, transactions: (userId: string) => `user:${userId}:transactions`, dashboard: (userId: string) => `user:${userId}:dashboard`, connections: (userId: string) => `user:${userId}:connections`, settings: (userId: string) => `user:${userId}:settings`, } export const DataTags = { CATEGORIES: 'data:categories', INSTITUTIONS: 'data:institutions', BENCHMARKS: 'data:benchmarks', } export const ContentTags = { POSTS: 'content:posts', HELP: 'content:help', MARKETING: 'content:marketing', } // Usage import { UserTags } from '@/lib/cache/tags' export async function getUserAccounts(userId: string) { 'use cache' cacheTag(UserTags.accounts(userId)) return await db.query.accounts.findMany(...) } ``` ### Supabase Client Selection ```ts // Client Components / Browser import { createClient } from '@/lib/db/supabase/browser' // Server Components / API Routes import { createClient } from '@/lib/db/supabase/server' // Middleware import { createClient } from '@/lib/db/supabase/middleware' // DAL (preferred for auth) import { getUserId, getUser } from '@/lib/data/dal' ``` ### Known Patterns ```ts // ✅ High-sophistication patterns in Clarity - DAL Pattern: verifySession(), getUserId(), getUser() - Repository Pattern: findByUserId(), findById() - Cache Components: 'use cache' with cacheLife() - Service Layer: Business logic in /lib/db/services - Barrel Exports: from '@/lib/utils' ``` ## Migration Guides ### Migrating to DAL ```ts // ❌ BEFORE - Direct Supabase import { createClient } from '@/lib/db/supabase/server' export default async function Page() { const supabase = await createClient() const { data: { user }, error } = await supabase.auth.getUser() if (error || !user) { redirect('/sign-in') } const data = await fetchData(user.id) return } // ✅ AFTER - Using DAL import { getUserId } from '@/lib/data/dal' export default async function Page() { const userId = await getUserId() // Auto-redirects if unauthenticated const data = await fetchData(userId) return } ``` ### Migrating to Type Centralization ```ts // ❌ BEFORE - Local type // components/TransactionList.tsx interface Transaction { id: string amount: number date: string } export function TransactionList({ transactions }: { transactions: Transaction[] }) { return
    ...
} // ✅ AFTER - Canonical type import type { Transaction } from '@/lib/types' export function TransactionList({ transactions }: { transactions: Transaction[] }) { return
    ...
} ``` ### Migrating to Repositories ```ts // ❌ BEFORE - Direct queries import { db } from '@/lib/db' import { accounts } from '@/lib/db/schema' import { eq } from 'drizzle-orm' export async function getAccounts(userId: string) { return await db.query.accounts.findMany({ where: eq(accounts.userId, userId), }) } // ✅ AFTER - Repository import * as AccountRepository from '@/lib/db/repositories/accounts' export async function getAccounts(userId: string) { return await AccountRepository.findByUserId(userId) } ``` ## Anti-Patterns Specific to Clarity ### ❌ Bypassing DAL ```ts // Direct Supabase auth calls const { data: { user } } = await supabase.auth.getUser() ``` ### ❌ Type Duplication ```ts // Defining domain types locally interface Transaction { ... } interface Account { ... } ``` ### ❌ Direct Balance Decryption ```ts // No fallback to metadata const balance = decryptBalance(account.balance, key) ``` ### ❌ Wrong Import Paths ```ts // Importing Drizzle operators from wrong place import { eq, and } from '@/lib/db' // Importing types from wrong place import type { Transaction } from '@/lib/transactions/types' ``` ## Best Practices ### 1. Always Use DAL for Auth ```ts // Server Components import { getUserId } from '@/lib/data/dal' // Client Components import { useAuthUser } from '@/hooks/use-auth-user' ``` ### 2. Import Types from @/lib/types ```ts import type { Transaction, Account, User, Connection, } from '@/lib/types' ``` ### 3. Use Repositories for Data Access ```ts import * as Repository from '@/lib/db/repositories/[name]' ``` ### 4. Use Balance Helpers ```ts import { getAccountBalance } from '@/lib/db/utils/balance-helpers' ``` ### 5. Correct Drizzle Imports ```ts import { eq, and, or } from 'drizzle-orm' ``` ## Success Criteria Clarity-compliant code has: ✅ **DAL Usage** - All auth via getUserId(), verifySession() ✅ **Type Centralization** - Domain types from @/lib/types ✅ **Repository Pattern** - Data access via repositories ✅ **Balance Helpers** - Encryption-aware balance handling ✅ **Correct Imports** - Drizzle from drizzle-orm ✅ **Cache Integration** - UserTags for cache invalidation ✅ **Supabase Clients** - Correct client for context ✅ **Service Layer** - Business logic in services ✅ **No Type Duplication** - Reuse canonical types ## Resources - `/lib/README.md` - Full lib/ architecture guide - `/lib/types/ARCHITECTURE.md` - Type system documentation - `/.claude/DAL_MIGRATION_SUMMARY.md` - DAL migration guide - `/docs/lib-auth.md` - Auth patterns documentation