{"slug":"architecture/PROVIDER_AGNOSTIC_ARCHITECTURE","title":"Provider-Agnostic Architecture","section":"architecture","sectionLabel":"Architecture","status":"unclassified","type":"document","path":"architecture/PROVIDER_AGNOSTIC_ARCHITECTURE.mdx","bytes":9312,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n\n> **Tier C — Historical.** This document is a point-in-time snapshot preserved for reference. For current architecture, see [CANONICAL_PLATFORM_ARCHITECTURE.md](../architecture/CANONICAL_PLATFORM_ARCHITECTURE.md).\n\n## Overview\n\nIntegrateWise now supports **multiple auth and database providers** through an abstraction layer. You can switch between providers via environment configuration without changing application code.\n\n### Supported Combinations\n\n| Auth Provider | Database Provider | Description |\n|---------------|-------------------|-------------|\n| Supabase Auth | Supabase DB | Full Supabase stack (PostgreSQL) |\n| Supabase Auth | Cloudflare D1 | Auth via Supabase, DB via D1 |\n| Clerk Auth | Supabase DB | Auth via Clerk, DB via Supabase |\n| Clerk Auth | Cloudflare D1 | Full Cloudflare stack (Workers + D1) |\n\n## Architecture\n\n### Auth Abstraction Layer\n\n**Location:** `lib/auth/`\n\n**Interface:** `AuthProvider` (in `lib/auth/types.ts`)\n\n```typescript\ninterface AuthProvider {\n  getSession(): Promise<Session | null>\n  getCurrentUser(): Promise<User | null>\n  signUp(email, password, name?): Promise<User>\n  signIn(email, password): Promise<Session>\n  signOut(): Promise<void>\n  getUserById(userId): Promise<User | null>\n  updateUser(userId, updates): Promise<User>\n  deleteUser(userId): Promise<void>\n  provider: 'supabase' | 'clerk'\n}\n```\n\n**Implementations:**\n- `lib/auth/providers/supabase-auth.ts` - Supabase Auth implementation\n- `lib/auth/providers/clerk-auth.ts` - Clerk Auth implementation\n\n**Usage:**\n```typescript\n\nconst auth = getAuthProvider()\nconst user = await auth.getCurrentUser()\n```\n\n---\n\n### Database Abstraction Layer\n\n**Location:** `lib/db/`\n\n**Interface:** `DatabaseProvider` (in `lib/db/types.ts`)\n\n```typescript\ninterface DatabaseProvider {\n  query<T>(sql, params?, options?): Promise<QueryResult<T>>\n  insert<T>(table, data, options?): Promise<QueryResult<T>>\n  update<T>(table, updates, where, options?): Promise<QueryResult<T>>\n  delete(table, where, options?): Promise<QueryResult>\n  raw<T>(sql, params?, options?): Promise<QueryResult<T>>\n  beginTransaction(): Promise<void>\n  commit(): Promise<void>\n  rollback(): Promise<void>\n  healthCheck(): Promise<boolean>\n  provider: 'supabase' | 'd1'\n}\n```\n\n**Implementations:**\n- `lib/db/providers/supabase-db.ts` - Supabase PostgreSQL implementation\n- `lib/db/providers/d1-db.ts` - Cloudflare D1 implementation\n\n**Usage:**\n```typescript\n\nconst db = getDatabaseProvider()\nconst result = await db.query('SELECT * FROM users WHERE id = ?', [userId])\n```\n\n---\n\n## Configuration\n\n### Environment Variables\n\n**Auth Provider Selection:**\n```bash\n# Set to 'supabase' or 'clerk'\nNEXT_PUBLIC_AUTH_PROVIDER=clerk\n```\n\n**Database Provider Selection:**\n```bash\n# Set to 'supabase' or 'd1'\nNEXT_PUBLIC_DB_PROVIDER=d1\n```\n\n### Supabase Credentials (if using Supabase)\n\n```bash\nNEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co\nNEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key\nSUPABASE_SERVICE_ROLE_KEY=your-service-key\n```\n\n### Clerk Credentials (if using Clerk)\n\n```bash\nNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...\nCLERK_SECRET_KEY=sk_test_...\n```\n\n### Deployment (Cloudflare)\n\nFor D1 database, add to `wrangler.toml`:\n```toml\n[[d1_databases]]\nbinding = \"DB\"\ndatabase_name = \"integratewise\"\ndatabase_id = \"your-db-id\"\n```\n\n---\n\n## Usage Examples\n\n### Example 1: Get Current User (Auth Agnostic)\n\n```typescript\n// Works with both Supabase and Clerk\n\nexport async function getCurrentUserAction() {\n  const auth = getAuthProvider()\n  const user = await auth.getCurrentUser()\n  return user\n}\n```\n\n### Example 2: Query Database (DB Agnostic)\n\n```typescript\n// Works with both Supabase and D1\n\nexport async function getUserData(userId: string) {\n  const db = getDatabaseProvider()\n  const result = await db.query(\n    'SELECT * FROM users WHERE id = ?',\n    [userId]\n  )\n  return result.data?.[0]\n}\n```\n\n### Example 3: Transaction (DB Agnostic)\n\n```typescript\n\nexport async function transferCredits(fromId: string, toId: string, amount: number) {\n  const db = getDatabaseProvider()\n\n  try {\n    await db.beginTransaction()\n\n    // Deduct from sender\n    await db.update(\n      'users',\n      { credits: db.raw('credits - ?', [amount]) },\n      { id: fromId }\n    )\n\n    // Add to receiver\n    await db.update(\n      'users',\n      { credits: db.raw('credits + ?', [amount]) },\n      { id: toId }\n    )\n\n    await db.commit()\n  } catch (error) {\n    await db.rollback()\n    throw error\n  }\n}\n```\n\n### Example 4: Check Provider (Advanced)\n\n```typescript\nimport { \n  isSupabaseAuth, \n  isClerkAuth, \n  isSupabaseDatabase, \n  isD1Database \n} from '@/lib/auth/factory'\n\n// Can provide provider-specific optimizations\nif (isClerkAuth()) {\n  // Clerk-specific logic\n}\n\nif (isD1Database()) {\n  // D1-specific optimizations\n}\n```\n\n---\n\n## File Structure\n\n```\napps/web/lib/\n├── auth/\n│   ├── types.ts                      # Auth provider interface\n│   ├── env.ts                        # Auth config\n│   ├── factory.ts                    # Auth provider factory\n│   └── providers/\n│       ├── supabase-auth.ts          # Supabase implementation\n│       └── clerk-auth.ts             # Clerk implementation\n└── db/\n    ├── types.ts                      # Database provider interface\n    ├── env.ts                        # Database config\n    ├── factory.ts                    # Database provider factory\n    └── providers/\n        ├── supabase-db.ts            # Supabase implementation\n        └── d1-db.ts                  # D1 implementation\n```\n\n---\n\n## Implementation Considerations\n\n### Supabase Auth\n\n**Pros:**\n- Full-featured auth system\n- RLS (Row Level Security) support\n- Built-in email verification\n- OAuth providers built-in\n\n**Cons:**\n- Requires Supabase account\n- Additional service dependency\n\n**When to use:**\n- Need advanced auth features\n- Using Supabase PostgreSQL for data\n- Need RLS policies\n\n### Clerk Auth\n\n**Pros:**\n- Modern auth UI/UX\n- No passwords option (passkeys, OAuth only)\n- Multi-tenancy support\n- Great developer experience\n\n**Cons:**\n- Another service dependency\n- Can't disable email/password if you want it\n\n**When to use:**\n- Want modern auth experience\n- Using D1 for data\n- Multi-tenant requirements\n\n### Supabase Database\n\n**Pros:**\n- Full PostgreSQL power\n- Built-in real-time subscriptions\n- RLS policies\n- Full SQL support\n\n**Cons:**\n- External service\n- Can be costly at scale\n- Network latency\n\n**When to use:**\n- Complex relational queries needed\n- Using Supabase Auth (same provider)\n- Need advanced features\n\n### Cloudflare D1\n\n**Pros:**\n- Zero cold starts (Workers)\n- Integrated with Cloudflare ecosystem\n- No external dependencies\n- Edge-optimized\n\n**Cons:**\n- SQLite (not PostgreSQL)\n- Fewer advanced features\n- Learning curve for distributed queries\n\n**When to use:**\n- Using Cloudflare Workers for backend\n- Deploying on Cloudflare stack\n- Want edge-first architecture\n\n---\n\n## Migration Guide\n\n### Switching from Supabase → Clerk Auth\n\n1. Update `.env.local`:\n```bash\nNEXT_PUBLIC_AUTH_PROVIDER=clerk\nNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...\nCLERK_SECRET_KEY=sk_...\n```\n\n2. Add ClerkProvider to `app/layout.tsx`:\n```typescript\n\n  return (\n    <ClerkProvider>\n      <html>{children}</html>\n    </ClerkProvider>\n  )\n}\n```\n\n3. No code changes needed! Factory automatically returns Clerk provider.\n\n### Switching from Supabase DB → D1\n\n1. Set up D1 in `wrangler.toml`\n2. Update `.env.local`:\n```bash\nNEXT_PUBLIC_DB_PROVIDER=d1\n```\n\n3. Optional: Add D1 migrations\n4. Code continues to work with factory\n\n---\n\n## Testing\n\n### Test with Supabase Stack\n\n```bash\nNEXT_PUBLIC_AUTH_PROVIDER=supabase\nNEXT_PUBLIC_DB_PROVIDER=supabase\nNEXT_PUBLIC_SUPABASE_URL=...\nNEXT_PUBLIC_SUPABASE_ANON_KEY=...\n```\n\n### Test with Cloudflare Stack\n\n```bash\nNEXT_PUBLIC_AUTH_PROVIDER=clerk\nNEXT_PUBLIC_DB_PROVIDER=d1\nNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=...\nCLERK_SECRET_KEY=...\n```\n\n### Test with Mixed Stack\n\n```bash\nNEXT_PUBLIC_AUTH_PROVIDER=clerk\nNEXT_PUBLIC_DB_PROVIDER=supabase\nNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=...\nCLERK_SECRET_KEY=...\nNEXT_PUBLIC_SUPABASE_URL=...\nNEXT_PUBLIC_SUPABASE_ANON_KEY=...\n```\n\n---\n\n## Best Practices\n\n1. **Always use factory functions**, never import providers directly\n2. **Only check provider when necessary** for optimizations\n3. **Keep business logic provider-agnostic**\n4. **Document provider-specific behavior** in comments\n5. **Test all supported combinations** before deployment\n6. **Use TypeScript** for compile-time safety\n7. **Handle errors gracefully** in provider implementations\n\n---\n\n## Future Enhancements\n\n- Add Firebase Auth support\n- Add AWS Cognito support\n- Add PostgreSQL (non-Supabase) support\n- Add MongoDB support\n- Add dynamic provider switching\n- Add provider health monitoring\n- Add metrics per provider\n\n"}