- {currentStep === 0 && "Choose your path and let's begin your journey"}
+ {currentStep === 0 &&
+ "Choose your path and let's begin your journey"}
{currentStep === 1 && "Help us know you better"}
{currentStep === 2 && "Tell us about your experience"}
{currentStep === 3 && "What are your interests?"}
{currentStep === 4 && "Select your primary focus area"}
- {currentStep === 5 && "Follow the arms you want to see in your feed"}
+ {currentStep === 5 &&
+ "Follow the arms you want to see in your feed"}
{currentStep === 6 && "Set up your creator profile"}
{currentStep === 7 && "You're ready to go!"}
diff --git a/client/pages/ethos/ArtistProfile.tsx b/client/pages/ethos/ArtistProfile.tsx
index 0fdf024e..e528eb83 100644
--- a/client/pages/ethos/ArtistProfile.tsx
+++ b/client/pages/ethos/ArtistProfile.tsx
@@ -72,7 +72,9 @@ export default function ArtistProfile() {
}
}
- const res = await fetch(`${API_BASE}/api/ethos/artists?id=${resolvedUserId}`);
+ const res = await fetch(
+ `${API_BASE}/api/ethos/artists?id=${resolvedUserId}`,
+ );
const data = await res.json();
setArtist(data);
} catch (error) {
diff --git a/docs/USERNAME-FIRST-UUID-FALLBACK.md b/docs/USERNAME-FIRST-UUID-FALLBACK.md
index dda9059b..a87c6574 100644
--- a/docs/USERNAME-FIRST-UUID-FALLBACK.md
+++ b/docs/USERNAME-FIRST-UUID-FALLBACK.md
@@ -5,6 +5,7 @@
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/` (also works)
- Users visit `/passport/alice-developer` (preferred) or `/passport/` (also works)
- Users visit `/ethos/artists/bob-musician` (preferred) or `/ethos/artists/` (also works)
@@ -18,15 +19,16 @@ This means:
**New file** that provides helper functions:
```typescript
-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
+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
@@ -41,6 +43,7 @@ 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)
@@ -49,6 +52,7 @@ GET /api/creators/550e8400-... // ✅ UUID lookup fallback
### 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
@@ -57,6 +61,7 @@ GET /api/creators/550e8400-... // ✅ UUID lookup fallback
### 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
@@ -65,6 +70,7 @@ GET /api/creators/550e8400-... // ✅ UUID lookup fallback
### 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
@@ -74,12 +80,12 @@ GET /api/creators/550e8400-... // ✅ UUID lookup fallback
## 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 |
+| Route | Type | Status |
+| ---------------------------- | -------- | ------------------ |
+| `/creators/:identifier` | Frontend | ✅ Updated |
+| `/passport/:identifier` | Frontend | ✅ Already working |
+| `/ethos/artists/:identifier` | Frontend | ✅ Updated |
+| `/api/creators/:identifier` | Backend | ✅ Updated |
---
@@ -156,7 +162,8 @@ Return artist data ✅
```typescript
// 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;
+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);
@@ -166,6 +173,7 @@ function isUUID(str: string): boolean {
### 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
@@ -184,12 +192,12 @@ For any identifier:
### Using the Resolver Utilities
```typescript
-import {
- isUUID,
+import {
+ isUUID,
resolveIdentifierToCreator,
resolveIdentifierToUserId,
- resolveIdentifierToUsername
-} from '@/lib/identifier-resolver';
+ resolveIdentifierToUsername,
+} from "@/lib/identifier-resolver";
// Check if string is UUID
if (isUUID(userInput)) {
@@ -297,4 +305,3 @@ code/
✅ **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.
-
diff --git a/server/index.ts b/server/index.ts
index e96b16af..74b595d7 100644
--- a/server/index.ts
+++ b/server/index.ts
@@ -435,7 +435,9 @@ export function createServer() {
if (error || !project) {
console.log("[Passport Data API] Project not found:", projectSlug);
- return res.status(404).json({ error: "Project not found", projectSlug });
+ return res
+ .status(404)
+ .json({ error: "Project not found", projectSlug });
}
return res.json({
@@ -4446,7 +4448,10 @@ export function createServer() {
}
// Check if identifier is a UUID (username-first, UUID fallback)
- const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(identifier);
+ const isUUID =
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
+ identifier,
+ );
let query = adminSupabase
.from("aethex_creators")
@@ -4477,11 +4482,16 @@ export function createServer() {
// If username lookup failed and it's a valid UUID format, try UUID
if (error && !isUUID) {
- if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(identifier)) {
- const { data: creatorByUUID, error: uuidError } = await adminSupabase
- .from("aethex_creators")
- .select(
- `
+ if (
+ /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
+ identifier,
+ )
+ ) {
+ const { data: creatorByUUID, error: uuidError } =
+ await adminSupabase
+ .from("aethex_creators")
+ .select(
+ `
id,
username,
bio,
@@ -4493,10 +4503,10 @@ export function createServer() {
created_at,
updated_at
`,
- )
- .eq("is_discoverable", true)
- .eq("id", identifier)
- .single();
+ )
+ .eq("is_discoverable", true)
+ .eq("id", identifier)
+ .single();
if (!uuidError && creatorByUUID) {
// Found by UUID, optionally redirect to username canonical URL