Systems

Architecture patterns coordinating multiple components

What are Systems?

Systems are architecture patterns that coordinate multiple components to achieve a specific capability. They sit between Solutions (business outcomes) and Software (frameworks).

Every system on this page includes: component list, data flow, complete code, and production failure modes.

Available Systems

Pattern: Authentication System

Components

  • Supabase Auth: User management, sessions, OAuth providers
  • Next.js Middleware: Route protection at edge
  • Server Components: Secure data fetching
  • Client Components: Login UI, session state

Data Flow

  1. User visits protected route → Middleware checks session
  2. No session → Redirect to /login
  3. User submits login → Supabase creates session
  4. Session stored in httpOnly cookie → Secure from XSS
  5. Subsequent requests → Middleware validates session
  6. Valid session → Allow access, fetch user data server-side

Implementation

1. Middleware (Edge Protection)

// middleware.ts
// Dependencies (October 5, 2025):
// - Next.js: 15.5.4
// - @supabase/ssr: 0.7.1
// Last verified: 2025-10-05

import { createServerClient } from '@supabase/ssr';
import { NextResponse, type NextRequest } from 'next/server';

export async function middleware(request: NextRequest) {
  let response = NextResponse.next({ request });

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          return request.cookies.get(name)?.value;
        },
        set(name: string, value: string, options: any) {
          response.cookies.set({ name, value, ...options });
        },
        remove(name: string, options: any) {
          response.cookies.set({ name, value: '', ...options });
        },
      },
    }
  );

  const { data: { session } } = await supabase.auth.getSession();

  // Protect dashboard routes
  if (request.nextUrl.pathname.startsWith('/dashboard') && !session) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  return response;
}

export const config = {
  matcher: ['/dashboard/:path*'],
};

2. Server Component (Secure Data)

// app/dashboard/page.tsx
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';

export default async function Dashboard() {
  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          return cookies().get(name)?.value;
        },
      },
    }
  );

  const { data: { user } } = await supabase.auth.getUser();

  return (
    <div>
      <h1>Welcome, {user?.email}</h1>
      {/* Secure server-side rendered content */}
    </div>
  );
}

3. Client Component (Login UI)

// components/login-form.tsx
'use client';
import { createBrowserClient } from '@supabase/ssr';
import { useState } from 'react';

export function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const supabase = createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );

  async function handleLogin(e: React.FormEvent) {
    e.preventDefault();
    const { error } = await supabase.auth.signInWithPassword({
      email,
      password,
    });
    if (!error) window.location.href = '/dashboard';
  }

  return (
    <form onSubmit={handleLogin} className="space-y-4 max-w-md">
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
        className="w-full p-2 border rounded"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
        className="w-full p-2 border rounded"
      />
      <button
        type="submit"
        className="w-full p-2 bg-blue-600 text-white rounded"
      >
        Login
      </button>
    </form>
  );
}

What Breaks in Production

  • Cookie domain mismatch: localhost works, production fails.
    Fix: Set cookieOptions.domain correctly for your deployment.
  • Session refresh timing: Users logged out randomly.
    Fix: Call supabase.auth.refreshSession() in client layout.
  • Middleware infinite redirects: /login redirects to /login.
    Fix: Exclude /login from matcher config.
  • Server/client data mismatch: Hydration errors.
    Fix: Use server components for initial user data, sync with client.

How Systems Relate to Other Layers

  • Deliver Solutions: Authentication enables secure apps, user-specific features
  • Built with Software: Next.js middleware, React components, TypeScript types
  • Use Services: Supabase Auth ($0-25/mo), Vercel Edge ($0-20/mo)
  • Require Support: Monitor login failures, session timeouts, security alerts