aethex-forge/docs/USERNAME-FIRST-UUID-FALLBACK.md
Builder.io 906080dc7c Username-First with UUID Fallback Implementation
cgen-8c691e8960b24739afbf1da70cb4d0f2
2025-11-17 02:58:48 +00:00

8.9 KiB

Username-First with UUID Fallback

Overview

The entire system now uses usernames as the primary identifier with UUID fallback for all user/creator lookups across routes and APIs.

This means:

  • Users visit /creators/john-doe (preferred) or /creators/<uuid> (also works)
  • Users visit /passport/alice-developer (preferred) or /passport/<uuid> (also works)
  • Users visit /ethos/artists/bob-musician (preferred) or /ethos/artists/<uuid> (also works)

Changes Made

1. Core Utility: Identifier Resolver (code/lib/identifier-resolver.ts)

New file that provides helper functions:

isUUID(str)                          // Check if string is UUID format
resolveIdentifierToCreator(id)      // Resolve username/UUID → creator object
resolveIdentifierToUserId(id)       // Resolve username/UUID → UUID
resolveIdentifierToUsername(id)     // Resolve UUID → username

2. Creators API Endpoint (code/server/index.ts)

Updated GET /api/creators/:identifier to:

  • Accept username OR UUID in the :identifier parameter
  • Try username first (preferred)
  • Fall back to UUID lookup if username lookup fails
  • Return 404 if neither works
// Examples that now work:
GET /api/creators/john-doe          // ✅ Username lookup
GET /api/creators/550e8400-...      // ✅ UUID lookup fallback

3. Creators Profile Component (code/client/pages/creators/CreatorProfile.tsx)

Updated to:

  • Import UUID/identifier resolver helpers
  • Accept both username and UUID as route parameters
  • Resolve UUID to username for canonical URL redirect (optional)
  • Maintain backwards compatibility with old UUID-based URLs

4. Ethos Artist Profile (code/client/pages/ethos/ArtistProfile.tsx)

Updated to:

  • Import identifier resolver helpers
  • Accept both username and userId as route parameters
  • Resolve username → userId before API call
  • Handle both patterns seamlessly

5. Passport Profile (code/client/pages/ProfilePassport.tsx)

Already supported username-first with UUID fallback:

  • Has built-in isUuid() function
  • Tries getProfileByUsername() first
  • Falls back to getProfileById() if username lookup fails
  • No changes needed - already implemented!

6. Creator Profile Validation (code/api/creators.ts)

Enforced usernames as required:

  • Username must be provided when creating creator profile
  • Username must be unique (409 Conflict if duplicate)
  • Username is normalized to lowercase
  • Validation on both client and server

Routes That Support Username-First with UUID Fallback

Route Type Status
/creators/:identifier Frontend Updated
/passport/:identifier Frontend Already working
/ethos/artists/:identifier Frontend Updated
/api/creators/:identifier Backend Updated

How It Works: Flow Example

Username Lookup (Preferred)

User visits: /creators/john-doe
   ↓
CreatorProfile component
   ↓
Component calls: GET /api/creators/john-doe
   ↓
Server checks: isUUID("john-doe") → false
   ↓
Query database: SELECT * FROM aethex_creators WHERE username = "john-doe"
   ↓
Return creator data ✅

UUID Lookup (Fallback)

User visits: /creators/550e8400-e29b-41d4-a716-446655440000
   ↓
CreatorProfile component
   ↓
Component calls: GET /api/creators/550e8400-e29b-41d4-a716-446655440000
   ↓
Server checks: isUUID("550e8400-...") → true
   ↓
Query database: SELECT * FROM aethex_creators WHERE username = "550e8400-..."
   ↓
No match, try UUID fallback:
SELECT * FROM aethex_creators WHERE id = "550e8400-..."
   ↓
Return creator data ✅

Username Resolution (For Ethos Artists)

User visits: /ethos/artists/bob-musician
   ↓
ArtistProfile component
   ↓
Component calls: resolveIdentifierToUserId("bob-musician")
   ↓
Utility function calls: GET /api/creators/bob-musician
   ↓
Creator found! Extract user_id = "550e8400-..."
   ↓
Component calls: GET /api/ethos/artists?id=550e8400-...
   ↓
Return artist data ✅

Benefits

SEO-friendly URLs - Usernames are more human-readable than UUIDs Backwards compatible - Old UUID-based links still work Consistent behavior - All user profile routes work the same way User-friendly - Share /creators/john-doe instead of UUID Enforced usernames - Everyone has a username, eliminates UUID-only profiles


Implementation Details

UUID Detection

// UUID regex pattern (standard RFC 4122)
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;

function isUUID(str: string): boolean {
  return uuidPattern.test(str);
}

Lookup Priority

For any identifier:

  1. If it matches UUID pattern → Try UUID lookup directly
  2. If it doesn't match UUID pattern → Try username lookup first, then UUID fallback
  3. If both fail → Return 404 Not Found

Username Normalization

  • Usernames stored as lowercase
  • Lookups are case-insensitive
  • Users can visit /creators/John-Doe, /creators/JOHN-DOE, /creators/john-doe - all work
  • URLs always redirect to the canonical username (lowercase)

Client-Side API Functions

Using the Resolver Utilities

import { 
  isUUID, 
  resolveIdentifierToCreator,
  resolveIdentifierToUserId,
  resolveIdentifierToUsername 
} from '@/lib/identifier-resolver';

// Check if string is UUID
if (isUUID(userInput)) {
  // It's a UUID, use as user ID
}

// Resolve identifier to creator profile
const creator = await resolveIdentifierToCreator("john-doe");
// or
const creator = await resolveIdentifierToCreator("550e8400-...");

// Get just the user ID
const userId = await resolveIdentifierToUserId("john-doe");

// Get just the username
const username = await resolveIdentifierToUsername("550e8400-...");

Database Consistency

Username Uniqueness

  • Usernames are unique in aethex_creators table
  • Enforced in API validation (returns 409 if duplicate)
  • Usernames are indexed for fast lookups

Required Field

  • username column is NOT NULL
  • All profiles created after enforcement have usernames
  • Migration: Existing profiles without usernames should be given auto-generated usernames

Future Improvements

  1. Profile slugs - Use human-friendly slugs instead of usernames (e.g., /profile/john-doe-developer)
  2. Username changes - Allow users to change usernames with proper redirects
  3. Vanity URLs - Custom profile URLs (e.g., /john)
  4. Social aliases - Link multiple usernames to one profile

Testing

Test Cases

✅ GET /api/creators/john-doe          → Returns creator
✅ GET /api/creators/JOHN-DOE          → Returns same creator (case-insensitive)
✅ GET /api/creators/550e8400-...      → Returns creator (UUID fallback)
✅ GET /api/creators/nonexistent       → Returns 404
✅ GET /api/creators/invalid-uuid      → Tries username, then returns 404

✅ /creators/john-doe                  → Loads profile
✅ /creators/550e8400-...              → Loads profile (UUID fallback)
✅ /passport/john-doe                  → Loads passport
✅ /passport/550e8400-...              → Loads passport (UUID fallback)
✅ /ethos/artists/bob-musician         → Loads artist
✅ /ethos/artists/550e8400-...         → Loads artist (UUID fallback)

Migration Checklist

  • Create identifier resolver utility
  • Update creators API endpoint to support both username and UUID
  • Update CreatorProfile component to handle both patterns
  • Update ArtistProfile component to handle both patterns
  • Enforce usernames as required field
  • Document the implementation
  • TODO: Migrate any existing profiles without usernames to auto-generated usernames
  • TODO: Add URL redirects for canonical username-based URLs
  • TODO: Update all link generation to prefer usernames

Files Modified

code/
├── lib/
│   └── identifier-resolver.ts          (NEW - UUID/username detection)
├── api/
│   └── creators.ts                     (UPDATED - enforce username required)
├── server/
│   └── index.ts                        (UPDATED - /api/creators/:identifier)
├── client/
│   ├── pages/
│   │   ├── creators/CreatorProfile.tsx (UPDATED - UUID fallback)
│   │   ├── ethos/ArtistProfile.tsx     (UPDATED - UUID fallback)
│   │   └── ProfilePassport.tsx         (NO CHANGE - already working)
│   └── App.tsx                         (NO CHANGE - routes unchanged)
└── docs/
    └── USERNAME-FIRST-UUID-FALLBACK.md (NEW - this file)

Summary

Username-First with UUID Fallback is now implemented across the entire system.

All user-facing routes and APIs prefer usernames while maintaining backward compatibility with UUID-based URLs. Users must have a username to create a profile, ensuring consistent, SEO-friendly URLs throughout the AeThex ecosystem.