aethex-forge/docs/PASSPORT-ARCHITECTURE.md
2025-11-17 04:20:27 +00:00

8.1 KiB
Raw Blame History

Passport Architecture: Foundation as Sole Issuer

Overview

aethex.foundation is the sole issuer and authority for all user passports/identities in the AeThex ecosystem. All other platforms (aethex.dev, future platforms) are OAuth clients that consume Foundation-issued identities.

This document defines the passport architecture and data flow.

Core Principle

Foundation = Single Source of Truth (SSOT) for identity
Each Platform = Read-only cache of Foundation passport data

Architecture

1. Foundation (aethex.foundation)

  • Owner of passport data
  • Issues and maintains all user identities
  • Provides OAuth endpoints for authentication
  • Provides passport API endpoints for clients to fetch user data
  • Single authority for all identity mutations (updates, deletions)

2. Client Platforms (aethex.dev, etc.)

  • Consumers of Foundation identities
  • Cache Foundation passport data locally for performance
  • Use cached data for reads (lookups, profile queries)
  • Forward any profile updates to Foundation's API
  • Validate passport integrity on each login

Data Flow

User Login Flow

User → Login → Redirect to Foundation
    ↓
Foundation (OAuth) → Verify credentials
    ↓
Return access_token + user data to aethex.dev
    ↓
aethex.dev (callback handler):
  1. Exchange code for token with Foundation
  2. Fetch userinfo from Foundation API
  3. Validate passport is complete
  4. SYNC (one-way) to local cache:
     - User profile data (from Foundation)
     - Achievements (from Foundation)
     - Projects (from Foundation)
  5. Create session on aethex.dev
    ↓
User authenticated, using Foundation passport

Profile Update Flow

User edits profile on aethex.dev
    ↓
aethex.dev validates input locally
    ↓
Forward update request to Foundation API
    ↓
Foundation (SSOT) validates and applies changes
    ↓
Foundation returns updated passport
    ↓
aethex.dev syncs updated data to local cache
    ↓
Update confirmed to user

Profile Read Flow

User/App requests profile on aethex.dev
    ↓
Check local cache
    ↓
If cache valid: Return cached data
If cache stale: Refresh from Foundation → update cache → return
    ↓
Never modify local cache outside of sync operations

Key Rules

ALLOWED Operations on aethex.dev

  1. Read from local cache - Fast lookups of passport data
  2. Sync from Foundation - One-way data import during login/refresh
  3. Validate against cache - Use cached data for access control
  4. Forward to Foundation - Route update requests to Foundation API
  5. Cache invalidation - Clear stale cache on logout or explicit refresh

FORBIDDEN Operations on aethex.dev

  1. Direct writes to passport data - All identity mutations must go through Foundation
  2. Creating new passports - Only Foundation can issue identities
  3. Modifying cached data - Cache is read-only except during sync
  4. Trusting unvalidated data - Always verify data came from Foundation

Database Schema (aethex.dev)

-- Local cache of Foundation passport data
CREATE TABLE user_profiles (
  id UUID PRIMARY KEY,                    -- Foundation user ID (immutable)
  email TEXT UNIQUE NOT NULL,             -- From Foundation
  username TEXT UNIQUE,                   -- From Foundation
  full_name TEXT,                         -- From Foundation
  avatar_url TEXT,                        -- From Foundation
  profile_completed BOOLEAN DEFAULT false,-- From Foundation

  -- Sync tracking
  foundation_synced_at TIMESTAMP,         -- When last synced from Foundation
  cache_valid_until TIMESTAMP,            -- When cache expires

  -- Local metadata (not from Foundation)
  last_login_at TIMESTAMP,                -- aethex.dev tracking only
  created_at TIMESTAMP,
  updated_at TIMESTAMP
);

-- Data from Foundation that shouldn't be written locally
-- (achievements, projects, etc. are fetched on-demand)

Sync Mechanism

Initial Sync (On Login)

  1. User authenticates with Foundation
  2. aethex.dev receives access_token and basic user info
  3. aethex.dev calls Foundation's /api/oauth/userinfo endpoint
  4. All user data from Foundation gets UPSERTED to local cache
  5. foundation_synced_at timestamp is updated

Periodic Sync (Background)

Every 24 hours (or on explicit request):
  1. Fetch current user data from Foundation API
  2. Compare with local cache
  3. If Foundation data differs: update cache
  4. If local cache is newer: ERROR (shouldn't happen)
  5. Update `cache_valid_until` timestamp

Cache Expiration

If (now > cache_valid_until):
  1. Treat cache as stale
  2. Fetch fresh from Foundation
  3. Update cache and expiration

Error Handling

What if Foundation is unavailable?

During Login:

  • <EFBFBD><EFBFBD> Cannot proceed - user must authenticate through Foundation
  • Return error: "Identity service unavailable"

For existing users (cache valid):

  • Can use cached data temporarily
  • Continue serving from cache
  • Log warning about Foundation unavailability
  • Retry sync in background

For profile updates:

  • Cannot proceed - updates must go through Foundation
  • Queue update locally, retry when Foundation is available
  • Or fail gracefully: "Identity service unavailable, please try again"

Validation Rules

On Every Auth Request

if (!user.foundation_synced_at) {
  throw new Error("User not synced from Foundation");
}

if (now > user.cache_valid_until) {
  // Refresh from Foundation
  await syncFromFoundation(user.id);
}

// User is authenticated and passport is valid

On Every Profile Update Request

// Forward to Foundation API, never write locally
const updated = await foundation.api.updateProfile(userId, changes);

// On success, sync response back to cache
await syncFromFoundation(userId);

return updated;

Migration from Old Model

Old Model: aethex.dev wrote directly to passport table New Model: aethex.dev only syncs FROM Foundation

Migration Steps

  1. Remove Foundation arm from aethex.dev UI (DONE)
  2. Clarify that aethex.dev is an OAuth client of Foundation (DONE)
  3. Make profile endpoints read-only, forward writes to Foundation
  4. Add cache validation on every auth request
  5. Implement background sync for cache freshness
  6. Monitor logs for any direct write attempts (should be 0)
  7. Deprecate old direct-write endpoints

API Endpoints Reference

Foundation APIs (Used by aethex.dev)

GET  /api/oauth/authorize       - Start OAuth flow
POST /api/oauth/token           - Exchange code for token
GET  /api/oauth/userinfo        - Fetch authenticated user's passport
GET  /api/users/:id             - Fetch specific user passport (public data)
PATCH /api/users/:id            - Update passport (requires auth)

aethex.dev APIs (Now read-only/cache-focused)

GET  /api/profile/:username     - Read from cache or fetch from Foundation
POST /api/profile/ensure        - Sync passport from Foundation (on login)
PATCH /api/profile/:id          - Forward to Foundation (no local writes)

Monitoring & Observability

Log these events

[Passport Sync] User synced from Foundation: {userId}
[Passport Error] User not found in Foundation: {userId}
[Passport Stale] Cache expired for user: {userId}, refreshing...
[Passport Write] Attempted direct write to local cache (FORBIDDEN): {userId}
[Passport Conflict] Local cache newer than Foundation (SYNC ERROR): {userId}

Metrics to track

  • Sync success rate (should be ~100%)
  • Cache hit rate (should be >95% for logged-in users)
  • Foundation API latency
  • Failed sync attempts
  • Stale cache detections

Future Enhancements

  1. Webhook sync - Foundation notifies clients when passport changes
  2. Event stream - Subscribe to passport update events
  3. Multi-version support - Handle different Foundation versions
  4. Distributed cache - Redis layer for cross-instance consistency
  5. Audit trail - Track all passport mutations at Foundation level
  • code/docs/PHASE3-SWITCHOVER-GUIDE.md - OAuth migration guide
  • code/api/auth/callback.ts - Login sync implementation
  • code/api/profile/ensure.ts - Profile sync endpoint