Prettier format pending files
This commit is contained in:
parent
b79ffaefbd
commit
81996f1040
10 changed files with 218 additions and 85 deletions
|
|
@ -49,19 +49,22 @@ export default async function handler(req: any, res: any) {
|
|||
const redirectUri = `${process.env.VITE_API_BASE || "https://aethex.dev"}/api/discord/oauth/callback`;
|
||||
|
||||
// Exchange code for access token
|
||||
const tokenResponse = await fetch("https://discord.com/api/v10/oauth2/token", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
const tokenResponse = await fetch(
|
||||
"https://discord.com/api/v10/oauth2/token",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
grant_type: "authorization_code",
|
||||
code,
|
||||
redirect_uri: redirectUri,
|
||||
}).toString(),
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
grant_type: "authorization_code",
|
||||
code,
|
||||
redirect_uri: redirectUri,
|
||||
}).toString(),
|
||||
});
|
||||
);
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
const errorData = await tokenResponse.json();
|
||||
|
|
@ -115,19 +118,23 @@ export default async function handler(req: any, res: any) {
|
|||
} else {
|
||||
// Create new user
|
||||
// First create auth user
|
||||
const { data: authData, error: authError } = await supabase.auth.admin.createUser({
|
||||
email: discordUser.email,
|
||||
email_confirm: true,
|
||||
user_metadata: {
|
||||
full_name: discordUser.username,
|
||||
avatar_url: discordUser.avatar
|
||||
? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png`
|
||||
: null,
|
||||
},
|
||||
});
|
||||
const { data: authData, error: authError } =
|
||||
await supabase.auth.admin.createUser({
|
||||
email: discordUser.email,
|
||||
email_confirm: true,
|
||||
user_metadata: {
|
||||
full_name: discordUser.username,
|
||||
avatar_url: discordUser.avatar
|
||||
? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png`
|
||||
: null,
|
||||
},
|
||||
});
|
||||
|
||||
if (authError || !authData.user) {
|
||||
console.error("[Discord OAuth] Auth user creation failed:", authError);
|
||||
console.error(
|
||||
"[Discord OAuth] Auth user creation failed:",
|
||||
authError,
|
||||
);
|
||||
return res.redirect("/login?error=auth_create");
|
||||
}
|
||||
|
||||
|
|
@ -135,17 +142,22 @@ export default async function handler(req: any, res: any) {
|
|||
isNewUser = true;
|
||||
|
||||
// Create user profile
|
||||
const { error: profileError } = await supabase.from("user_profiles").insert({
|
||||
id: userId,
|
||||
email: discordUser.email,
|
||||
full_name: discordUser.username,
|
||||
avatar_url: discordUser.avatar
|
||||
? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png`
|
||||
: null,
|
||||
});
|
||||
const { error: profileError } = await supabase
|
||||
.from("user_profiles")
|
||||
.insert({
|
||||
id: userId,
|
||||
email: discordUser.email,
|
||||
full_name: discordUser.username,
|
||||
avatar_url: discordUser.avatar
|
||||
? `https://cdn.discordapp.com/avatars/${discordUser.id}/${discordUser.avatar}.png`
|
||||
: null,
|
||||
});
|
||||
|
||||
if (profileError) {
|
||||
console.error("[Discord OAuth] Profile creation failed:", profileError);
|
||||
console.error(
|
||||
"[Discord OAuth] Profile creation failed:",
|
||||
profileError,
|
||||
);
|
||||
return res.redirect("/login?error=profile_create");
|
||||
}
|
||||
}
|
||||
|
|
@ -164,9 +176,10 @@ export default async function handler(req: any, res: any) {
|
|||
}
|
||||
|
||||
// Generate session token
|
||||
const { data: sessionData, error: sessionError } = await supabase.auth.admin.createSession({
|
||||
user_id: userId,
|
||||
});
|
||||
const { data: sessionData, error: sessionError } =
|
||||
await supabase.auth.admin.createSession({
|
||||
user_id: userId,
|
||||
});
|
||||
|
||||
if (sessionError || !sessionData.session) {
|
||||
console.error("[Discord OAuth] Session creation failed:", sessionError);
|
||||
|
|
@ -189,7 +202,7 @@ export default async function handler(req: any, res: any) {
|
|||
|
||||
const redirectUrl = new URL(
|
||||
nextPath,
|
||||
process.env.VITE_API_BASE || "https://aethex.dev"
|
||||
process.env.VITE_API_BASE || "https://aethex.dev",
|
||||
);
|
||||
res.redirect(redirectUrl.toString());
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,12 @@ export default function DocsHeroSection({
|
|||
Get Started
|
||||
</Link>
|
||||
</Button>
|
||||
<Button asChild variant="outline" size="lg" className={outlineButtonClass}>
|
||||
<Button
|
||||
asChild
|
||||
variant="outline"
|
||||
size="lg"
|
||||
className={outlineButtonClass}
|
||||
>
|
||||
<Link to="/docs/tutorials">
|
||||
<Play className="h-5 w-5 mr-2" />
|
||||
Watch Tutorials
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ export default function DocsLayout({
|
|||
return docNavigation.filter(
|
||||
(item) =>
|
||||
item.title.toLowerCase().includes(query) ||
|
||||
item.description?.toLowerCase().includes(query)
|
||||
item.description?.toLowerCase().includes(query),
|
||||
);
|
||||
}, [searchQuery]);
|
||||
|
||||
|
|
@ -139,21 +139,26 @@ export default function DocsLayout({
|
|||
}`}
|
||||
>
|
||||
{/* AeThex Branding */}
|
||||
<div className={`p-6 border-b ${colors.border} flex flex-col items-center justify-center`}>
|
||||
<div
|
||||
className={`p-6 border-b ${colors.border} flex flex-col items-center justify-center`}
|
||||
>
|
||||
<Link
|
||||
to="/docs"
|
||||
className="flex flex-col items-center justify-center gap-4 w-full"
|
||||
>
|
||||
<img
|
||||
src={theme === "professional"
|
||||
? "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2Fbac6154f77e94521bcbfe35abd605cd0?format=webp&width=800"
|
||||
: "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2F1d007dd573c54339ad35fde9cd637516?format=webp&width=800"
|
||||
src={
|
||||
theme === "professional"
|
||||
? "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2Fbac6154f77e94521bcbfe35abd605cd0?format=webp&width=800"
|
||||
: "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2F1d007dd573c54339ad35fde9cd637516?format=webp&width=800"
|
||||
}
|
||||
alt="AeThex Logo"
|
||||
className="h-16 w-16 object-contain"
|
||||
/>
|
||||
<div className="text-center">
|
||||
<div className={`font-bold text-lg ${colors.headingColor}`}>AeThex</div>
|
||||
<div className={`font-bold text-lg ${colors.headingColor}`}>
|
||||
AeThex
|
||||
</div>
|
||||
<div className={`text-xs ${colors.textMuted}`}>Documentation</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
|
@ -190,7 +195,9 @@ export default function DocsLayout({
|
|||
{/* Search Bar */}
|
||||
<div className={`p-4 border-b ${colors.border}`}>
|
||||
<div className="relative">
|
||||
<Search className={`absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 ${colors.textMuted}`} />
|
||||
<Search
|
||||
className={`absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 ${colors.textMuted}`}
|
||||
/>
|
||||
<Input
|
||||
placeholder="Search docs..."
|
||||
className={`${colors.inputBg} border-${colors.border} pl-10 pr-4 text-sm ${colors.foreground}`}
|
||||
|
|
@ -202,7 +209,9 @@ export default function DocsLayout({
|
|||
|
||||
{/* Navigation */}
|
||||
<nav className="p-4 space-y-1">
|
||||
<div className={`text-xs font-semibold ${colors.textMuted} uppercase tracking-wider mb-4 px-2`}>
|
||||
<div
|
||||
className={`text-xs font-semibold ${colors.textMuted} uppercase tracking-wider mb-4 px-2`}
|
||||
>
|
||||
Documentation
|
||||
</div>
|
||||
{filteredNav.map((item) => (
|
||||
|
|
@ -249,7 +258,9 @@ export default function DocsLayout({
|
|||
{/* Main Content */}
|
||||
<main className="md:ml-64">
|
||||
{/* Mobile Header */}
|
||||
<div className={`md:hidden sticky top-0 z-20 border-b ${colors.border} ${colors.cardBg} p-4 flex items-center justify-between`}>
|
||||
<div
|
||||
className={`md:hidden sticky top-0 z-20 border-b ${colors.border} ${colors.cardBg} p-4 flex items-center justify-between`}
|
||||
>
|
||||
<button
|
||||
onClick={() => setSidebarOpen(!sidebarOpen)}
|
||||
className={`p-2 ${colors.sidebarHover} rounded-lg`}
|
||||
|
|
@ -270,7 +281,11 @@ export default function DocsLayout({
|
|||
<div className="lg:col-span-3">
|
||||
{title && (
|
||||
<div className="mb-8">
|
||||
<h1 className={`text-5xl font-bold ${colors.headingColor} mb-3`}>{title}</h1>
|
||||
<h1
|
||||
className={`text-5xl font-bold ${colors.headingColor} mb-3`}
|
||||
>
|
||||
{title}
|
||||
</h1>
|
||||
{description && (
|
||||
<p className={`text-lg ${colors.textMuted}`}>{description}</p>
|
||||
)}
|
||||
|
|
@ -278,7 +293,9 @@ export default function DocsLayout({
|
|||
)}
|
||||
|
||||
{/* Content - either children (for wrapper) or Outlet (for routing) */}
|
||||
<div className={`prose max-w-none ${theme === "professional" ? "prose-neutral" : "prose-invert"}`}>
|
||||
<div
|
||||
className={`prose max-w-none ${theme === "professional" ? "prose-neutral" : "prose-invert"}`}
|
||||
>
|
||||
{children || <Outlet />}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -287,7 +304,9 @@ export default function DocsLayout({
|
|||
{tableOfContents.length > 0 && (
|
||||
<aside className="hidden lg:block">
|
||||
<div className="sticky top-8">
|
||||
<div className={`text-xs font-semibold ${colors.textMuted} uppercase tracking-wider mb-4`}>
|
||||
<div
|
||||
className={`text-xs font-semibold ${colors.textMuted} uppercase tracking-wider mb-4`}
|
||||
>
|
||||
On this page
|
||||
</div>
|
||||
<nav className="space-y-2">
|
||||
|
|
@ -315,52 +334,76 @@ export default function DocsLayout({
|
|||
<div className="max-w-7xl mx-auto px-6 md:px-8 py-8">
|
||||
{/* AeThex Arms - Grayscale for professional, colored for brand */}
|
||||
<div className={`mb-8 pb-8 border-b ${colors.border}`}>
|
||||
<h3 className={`text-sm font-semibold ${colors.headingColor} mb-3`}>AeThex Platforms</h3>
|
||||
<h3
|
||||
className={`text-sm font-semibold ${colors.headingColor} mb-3`}
|
||||
>
|
||||
AeThex Platforms
|
||||
</h3>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{theme === "professional" ? (
|
||||
<>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-gray-200">
|
||||
<div className="h-2 w-2 rounded-full bg-gray-400"></div>
|
||||
<span className="text-xs font-medium text-gray-700">Labs</span>
|
||||
<span className="text-xs font-medium text-gray-700">
|
||||
Labs
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-gray-200">
|
||||
<div className="h-2 w-2 rounded-full bg-gray-400"></div>
|
||||
<span className="text-xs font-medium text-gray-700">GameForge</span>
|
||||
<span className="text-xs font-medium text-gray-700">
|
||||
GameForge
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-gray-200">
|
||||
<div className="h-2 w-2 rounded-full bg-gray-400"></div>
|
||||
<span className="text-xs font-medium text-gray-700">Corp</span>
|
||||
<span className="text-xs font-medium text-gray-700">
|
||||
Corp
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-gray-200">
|
||||
<div className="h-2 w-2 rounded-full bg-gray-400"></div>
|
||||
<span className="text-xs font-medium text-gray-700">Foundation</span>
|
||||
<span className="text-xs font-medium text-gray-700">
|
||||
Foundation
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-gray-200">
|
||||
<div className="h-2 w-2 rounded-full bg-gray-400"></div>
|
||||
<span className="text-xs font-medium text-gray-700">Dev-Link</span>
|
||||
<span className="text-xs font-medium text-gray-700">
|
||||
Dev-Link
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-yellow-100">
|
||||
<div className="h-2 w-2 rounded-full bg-yellow-500"></div>
|
||||
<span className="text-xs font-medium text-yellow-900">Labs</span>
|
||||
<span className="text-xs font-medium text-yellow-900">
|
||||
Labs
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-green-100">
|
||||
<div className="h-2 w-2 rounded-full bg-green-500"></div>
|
||||
<span className="text-xs font-medium text-green-900">GameForge</span>
|
||||
<span className="text-xs font-medium text-green-900">
|
||||
GameForge
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-blue-100">
|
||||
<div className="h-2 w-2 rounded-full bg-blue-500"></div>
|
||||
<span className="text-xs font-medium text-blue-900">Corp</span>
|
||||
<span className="text-xs font-medium text-blue-900">
|
||||
Corp
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-red-100">
|
||||
<div className="h-2 w-2 rounded-full bg-red-500"></div>
|
||||
<span className="text-xs font-medium text-red-900">Foundation</span>
|
||||
<span className="text-xs font-medium text-red-900">
|
||||
Foundation
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 px-3 py-1 rounded-lg bg-cyan-100">
|
||||
<div className="h-2 w-2 rounded-full bg-cyan-500"></div>
|
||||
<span className="text-xs font-medium text-cyan-900">Dev-Link</span>
|
||||
<span className="text-xs font-medium text-cyan-900">
|
||||
Dev-Link
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
|
@ -369,7 +412,9 @@ export default function DocsLayout({
|
|||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<div>
|
||||
<h3 className={`font-semibold ${colors.headingColor} mb-4`}>Product</h3>
|
||||
<h3 className={`font-semibold ${colors.headingColor} mb-4`}>
|
||||
Product
|
||||
</h3>
|
||||
<ul className={`space-y-2 text-sm ${colors.textMuted}`}>
|
||||
<li>
|
||||
<Link to="/docs" className={`${colors.accentHover}`}>
|
||||
|
|
@ -377,7 +422,10 @@ export default function DocsLayout({
|
|||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/docs/platform" className={`${colors.accentHover}`}>
|
||||
<Link
|
||||
to="/docs/platform"
|
||||
className={`${colors.accentHover}`}
|
||||
>
|
||||
Platform
|
||||
</Link>
|
||||
</li>
|
||||
|
|
@ -389,10 +437,15 @@ export default function DocsLayout({
|
|||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className={`font-semibold ${colors.headingColor} mb-4`}>Resources</h3>
|
||||
<h3 className={`font-semibold ${colors.headingColor} mb-4`}>
|
||||
Resources
|
||||
</h3>
|
||||
<ul className={`space-y-2 text-sm ${colors.textMuted}`}>
|
||||
<li>
|
||||
<Link to="/docs/tutorials" className={`${colors.accentHover}`}>
|
||||
<Link
|
||||
to="/docs/tutorials"
|
||||
className={`${colors.accentHover}`}
|
||||
>
|
||||
Tutorials
|
||||
</Link>
|
||||
</li>
|
||||
|
|
@ -409,7 +462,9 @@ export default function DocsLayout({
|
|||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className={`font-semibold ${colors.headingColor} mb-4`}>Community</h3>
|
||||
<h3 className={`font-semibold ${colors.headingColor} mb-4`}>
|
||||
Community
|
||||
</h3>
|
||||
<ul className={`space-y-2 text-sm ${colors.textMuted}`}>
|
||||
<li>
|
||||
<a href="#" className={`${colors.accentHover}`}>
|
||||
|
|
@ -429,7 +484,9 @@ export default function DocsLayout({
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`border-t ${colors.border} mt-8 pt-8 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 text-sm ${colors.textMuted}`}>
|
||||
<div
|
||||
className={`border-t ${colors.border} mt-8 pt-8 flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 text-sm ${colors.textMuted}`}
|
||||
>
|
||||
<p>© 2025 AeThex. All rights reserved.</p>
|
||||
<div className="flex gap-6">
|
||||
<a href="#" className={`${colors.accentHover}`}>
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@ export default function DocsSupportCTA({
|
|||
: "border-purple-400/60 text-purple-200";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`mt-12 rounded-2xl border ${ctaBg} p-8 text-center`}
|
||||
>
|
||||
<div className={`mt-12 rounded-2xl border ${ctaBg} p-8 text-center`}>
|
||||
<h3 className={`text-3xl font-semibold ${colors.headingColor} mb-4`}>
|
||||
{title}
|
||||
</h3>
|
||||
|
|
|
|||
|
|
@ -64,7 +64,9 @@ export default function LearningResourcesGrid({
|
|||
}: LearningResourcesGridProps) {
|
||||
const { colors, theme } = useDocsTheme();
|
||||
const hoverBorderColor =
|
||||
theme === "professional" ? "hover:border-gray-400" : "hover:border-purple-500/50";
|
||||
theme === "professional"
|
||||
? "hover:border-gray-400"
|
||||
: "hover:border-purple-500/50";
|
||||
|
||||
return (
|
||||
<div className="mb-12">
|
||||
|
|
|
|||
|
|
@ -99,11 +99,15 @@ export default function QuickStartSection({
|
|||
{cards.map((card, index) => {
|
||||
const Icon = card.icon;
|
||||
const hoverBorderColor =
|
||||
theme === "professional" ? "hover:border-gray-400" : "hover:border-purple-500/50";
|
||||
theme === "professional"
|
||||
? "hover:border-gray-400"
|
||||
: "hover:border-purple-500/50";
|
||||
const iconColor =
|
||||
theme === "professional" ? "text-gray-700" : "text-purple-400";
|
||||
const hoverTitleColor =
|
||||
theme === "professional" ? "group-hover:text-gray-900" : "group-hover:text-purple-400";
|
||||
theme === "professional"
|
||||
? "group-hover:text-gray-900"
|
||||
: "group-hover:text-purple-400";
|
||||
|
||||
return (
|
||||
<Card
|
||||
|
|
|
|||
|
|
@ -49,7 +49,9 @@ export default function RecentUpdatesSection({
|
|||
? "border-gray-300 text-black hover:bg-gray-100"
|
||||
: "border-slate-600 text-white hover:bg-slate-800";
|
||||
const hoverBorderColor =
|
||||
theme === "professional" ? "hover:border-gray-400" : "hover:border-purple-500/50";
|
||||
theme === "professional"
|
||||
? "hover:border-gray-400"
|
||||
: "hover:border-purple-500/50";
|
||||
|
||||
return (
|
||||
<div className="mb-12">
|
||||
|
|
|
|||
|
|
@ -93,12 +93,18 @@ export default function ResourceSectionsGrid({
|
|||
sections = defaultSections,
|
||||
}: ResourceSectionsGridProps) {
|
||||
const { colors, theme } = useDocsTheme();
|
||||
const iconColor = theme === "professional" ? "text-gray-700" : "text-purple-400";
|
||||
const iconColor =
|
||||
theme === "professional" ? "text-gray-700" : "text-purple-400";
|
||||
const hoverBorderColor =
|
||||
theme === "professional" ? "hover:border-gray-400" : "hover:border-purple-500/50";
|
||||
theme === "professional"
|
||||
? "hover:border-gray-400"
|
||||
: "hover:border-purple-500/50";
|
||||
const hoverTitleColor =
|
||||
theme === "professional" ? "group-hover:text-gray-900" : "group-hover:text-purple-400";
|
||||
const arrowColor = theme === "professional" ? "text-gray-600" : "text-purple-400";
|
||||
theme === "professional"
|
||||
? "group-hover:text-gray-900"
|
||||
: "group-hover:text-purple-400";
|
||||
const arrowColor =
|
||||
theme === "professional" ? "text-gray-600" : "text-purple-400";
|
||||
const explorehoverColor =
|
||||
theme === "professional"
|
||||
? "group-hover:text-gray-900"
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ interface DocsThemeContextType {
|
|||
}
|
||||
|
||||
const DocsThemeContext = createContext<DocsThemeContextType | undefined>(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
|
||||
export function DocsThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ This document provides a comprehensive analysis of the AETHEX project's actual t
|
|||
## 1. FRONTEND STACK (Vercel)
|
||||
|
||||
### Current Implementation
|
||||
|
||||
- **Framework**: Vite + React (Custom architecture)
|
||||
- **NOT Next.js** - This is a significant difference from the development plan
|
||||
- **Build Tool**: Vite for fast development and optimized production builds
|
||||
|
|
@ -19,6 +20,7 @@ This document provides a comprehensive analysis of the AETHEX project's actual t
|
|||
### Architecture Components
|
||||
|
||||
#### Page Structure
|
||||
|
||||
```
|
||||
code/client/pages/
|
||||
├── Auth Pages
|
||||
|
|
@ -52,6 +54,7 @@ code/client/pages/
|
|||
```
|
||||
|
||||
#### Context Providers
|
||||
|
||||
```
|
||||
code/client/contexts/
|
||||
├── AuthContext.tsx (User authentication state)
|
||||
|
|
@ -61,6 +64,7 @@ code/client/contexts/
|
|||
```
|
||||
|
||||
#### Key Components
|
||||
|
||||
```
|
||||
code/client/components/
|
||||
├── Layout.tsx (Main layout with header, navigation, footer)
|
||||
|
|
@ -87,6 +91,7 @@ code/client/components/
|
|||
```
|
||||
|
||||
### Authentication Methods Supported
|
||||
|
||||
1. **Email/Password** (Native Supabase)
|
||||
2. **GitHub OAuth** (Supabase)
|
||||
3. **Google OAuth** (Supabase)
|
||||
|
|
@ -95,6 +100,7 @@ code/client/components/
|
|||
6. **Web3/Ethereum** (Metamask signature verification)
|
||||
|
||||
### Critical Notes on Frontend
|
||||
|
||||
- ✅ Uses custom Supabase client (NOT the new @supabase/ssr package)
|
||||
- ⚠️ Does NOT use Next.js App Router or middleware
|
||||
- ⚠️ CSP headers need configuration in Vite for Discord Activity
|
||||
|
|
@ -108,6 +114,7 @@ code/client/components/
|
|||
### Database (PostgreSQL via Supabase)
|
||||
|
||||
#### Core Tables
|
||||
|
||||
```
|
||||
public.user_profiles
|
||||
├── id (UUID, PK)
|
||||
|
|
@ -129,6 +136,7 @@ auth.users (Managed by Supabase Auth)
|
|||
```
|
||||
|
||||
#### Discord Integration Tables
|
||||
|
||||
```
|
||||
public.discord_links
|
||||
├── discord_id (TEXT, PK)
|
||||
|
|
@ -161,6 +169,7 @@ public.discord_user_roles
|
|||
```
|
||||
|
||||
#### Creator Network Tables
|
||||
|
||||
```
|
||||
public.aethex_creators
|
||||
├── user_id (UUID, FK)
|
||||
|
|
@ -196,6 +205,7 @@ public.aethex_endorsements
|
|||
```
|
||||
|
||||
#### Web3 Integration
|
||||
|
||||
```
|
||||
public.web3_nonces
|
||||
├── wallet_address (TEXT, PK)
|
||||
|
|
@ -210,6 +220,7 @@ user_profiles extensions:
|
|||
```
|
||||
|
||||
#### Game Integration
|
||||
|
||||
```
|
||||
public.game_auth_tokens
|
||||
├── id (UUID, PK)
|
||||
|
|
@ -229,6 +240,7 @@ public.game_sessions
|
|||
### Row Level Security (RLS) Status
|
||||
|
||||
**Current State**: Basic RLS policies implemented
|
||||
|
||||
```sql
|
||||
-- Example: Users can see their own profile
|
||||
CREATE POLICY "User can see their own profile"
|
||||
|
|
@ -242,6 +254,7 @@ CREATE POLICY "User can update their own profile"
|
|||
```
|
||||
|
||||
**Status**: ⚠️ NOT YET OPTIMIZED (Plan recommends performance optimization)
|
||||
|
||||
```sql
|
||||
-- Should be optimized to:
|
||||
CREATE POLICY "User can see their own profile"
|
||||
|
|
@ -254,14 +267,17 @@ CREATE POLICY "User can see their own profile"
|
|||
#### Location: `code/api/` directory
|
||||
|
||||
##### Discord OAuth
|
||||
|
||||
- `code/api/discord/oauth/start.ts` - GET endpoint, redirects to Discord
|
||||
- `code/api/discord/oauth/callback.ts` - GET endpoint, handles OAuth callback
|
||||
|
||||
##### Discord Linking & Verification
|
||||
|
||||
- `code/api/discord/verify-code.ts` - POST, verifies 6-digit code from /verify command
|
||||
- `code/api/discord/link.ts` - POST, links Discord account to user
|
||||
|
||||
##### Discord Management
|
||||
|
||||
- `code/api/discord/role-mappings.ts` - GET/POST/PUT/DELETE role mapping CRUD
|
||||
- `code/api/discord/sync-roles.ts` - POST, assigns Discord roles based on arm + user_type
|
||||
- `code/api/discord/admin-register-commands.ts` - POST, registers slash commands (requires admin token)
|
||||
|
|
@ -269,16 +285,19 @@ CREATE POLICY "User can see their own profile"
|
|||
- `code/api/discord/verify.ts` - POST, checks if user is linked to Discord
|
||||
|
||||
##### Creator Network
|
||||
|
||||
- `code/api/creators.ts` - GET/POST/PUT, manage creator profiles
|
||||
- `code/api/opportunities.ts` - GET/POST/PUT, manage job opportunities
|
||||
- `code/api/applications.ts` - GET/POST/PUT/DELETE, manage job applications
|
||||
|
||||
##### Game Integration
|
||||
|
||||
- `code/api/games/game-auth.ts` - POST, unified game authentication (Unity/Unreal/Godot/Roblox)
|
||||
- `code/api/games/roblox-auth.ts` - POST, Roblox-specific authentication
|
||||
- `code/api/games/verify-token.ts` - POST, verify game session tokens
|
||||
|
||||
##### Other
|
||||
|
||||
- `code/api/user/link-roblox.ts` - POST, link Roblox account
|
||||
- `code/api/user/link-web3.ts` - POST, link Ethereum wallet
|
||||
- `code/api/web3/nonce.ts` - POST, generate Web3 nonce
|
||||
|
|
@ -289,6 +308,7 @@ CREATE POLICY "User can see their own profile"
|
|||
**Location**: `code/server/index.ts`
|
||||
|
||||
**Responsibilities**:
|
||||
|
||||
- Discord slash command handlers (/creators, /opportunities, /nexus)
|
||||
- Discord interactions endpoint (signature verification)
|
||||
- Health check endpoints
|
||||
|
|
@ -296,6 +316,7 @@ CREATE POLICY "User can see their own profile"
|
|||
- Admin functions
|
||||
|
||||
**Key Features**:
|
||||
|
||||
- ED25519 signature verification for Discord requests
|
||||
- Slash command routing
|
||||
- Admin token validation (DISCORD_ADMIN_REGISTER_TOKEN)
|
||||
|
|
@ -306,6 +327,7 @@ CREATE POLICY "User can see their own profile"
|
|||
## 3. DISCORD BOT STACK (Railway)
|
||||
|
||||
### Current Deployment
|
||||
|
||||
- **Platform**: Railway (PaaS)
|
||||
- **Language**: Node.js with discord.js v14
|
||||
- **Hosting Status**: ✅ Successfully deployed and running
|
||||
|
|
@ -328,6 +350,7 @@ CREATE POLICY "User can see their own profile"
|
|||
### Implemented Slash Commands
|
||||
|
||||
#### 1. `/verify` (Account Linking)
|
||||
|
||||
- **File**: `code/discord-bot/commands/verify.js`
|
||||
- **Function**: Generates 15-minute verification code
|
||||
- **Flow**:
|
||||
|
|
@ -338,6 +361,7 @@ CREATE POLICY "User can see their own profile"
|
|||
5. discord_links record created
|
||||
|
||||
#### 2. `/set-realm` (Choose Primary Arm)
|
||||
|
||||
- **File**: `code/discord-bot/commands/set-realm.js`
|
||||
- **Function**: Dropdown menu to select primary arm
|
||||
- **Options**: labs, gameforge, corp, foundation, devlink, nexus
|
||||
|
|
@ -346,15 +370,18 @@ CREATE POLICY "User can see their own profile"
|
|||
2. Triggers role assignment via roleManager.js
|
||||
|
||||
#### 3. `/profile` (Show Profile)
|
||||
|
||||
- **File**: `code/discord-bot/commands/profile.js`
|
||||
- **Function**: Displays linked AeThex profile in Discord
|
||||
- **Shows**: Username, bio, avatar, primary realm, link to full profile
|
||||
|
||||
#### 4. `/unlink` (Disconnect Account)
|
||||
|
||||
- **File**: `code/discord-bot/commands/unlink.js`
|
||||
- **Function**: Removes Discord link and revokes roles
|
||||
|
||||
#### 5. `/verify-role` (Check Assigned Roles)
|
||||
|
||||
- **File**: `code/discord-bot/commands/verify-role.js`
|
||||
- **Function**: Shows current Discord roles and expected roles from mappings
|
||||
|
||||
|
|
@ -363,13 +390,14 @@ CREATE POLICY "User can see their own profile"
|
|||
```javascript
|
||||
// code/discord-bot/utils/roleManager.js
|
||||
{
|
||||
assignRoleByArm(discord_id, arm, server_id) // Assign role based on arm
|
||||
getUserArm(discord_id) // Get user's primary arm
|
||||
syncRolesAcrossGuilds(discord_id) // Sync roles in all servers
|
||||
assignRoleByArm(discord_id, arm, server_id); // Assign role based on arm
|
||||
getUserArm(discord_id); // Get user's primary arm
|
||||
syncRolesAcrossGuilds(discord_id); // Sync roles in all servers
|
||||
}
|
||||
```
|
||||
|
||||
### Dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"discord.js": "^14.13.0",
|
||||
|
|
@ -379,6 +407,7 @@ CREATE POLICY "User can see their own profile"
|
|||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```
|
||||
DISCORD_BOT_TOKEN=<bot token>
|
||||
DISCORD_CLIENT_ID=578971245454950421
|
||||
|
|
@ -390,6 +419,7 @@ BOT_PORT=3000
|
|||
```
|
||||
|
||||
### Bot Health Check
|
||||
|
||||
- **Endpoint**: POST /health
|
||||
- **Returns**: { status, guilds, commands, uptime, timestamp }
|
||||
- **Used by**: Frontend `/api/discord/bot-health` proxy
|
||||
|
|
@ -451,7 +481,9 @@ Redirects to /profile/settings
|
|||
```
|
||||
|
||||
### Discord Manifest
|
||||
|
||||
**Location**: `code/public/discord-manifest.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "578971245454950421",
|
||||
|
|
@ -470,6 +502,7 @@ Redirects to /profile/settings
|
|||
## 5. PLANNED vs. ACTUAL - KEY DIFFERENCES
|
||||
|
||||
### Development Plan Says... | Actually Have... | Status
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ FRONTEND │
|
||||
|
|
@ -528,6 +561,7 @@ Redirects to /profile/settings
|
|||
## 6. ENVIRONMENT VARIABLES (All Set)
|
||||
|
||||
### Supabase
|
||||
|
||||
```
|
||||
VITE_SUPABASE_URL=https://kmdeisowhtsalsekkzqd.supabase.co
|
||||
VITE_SUPABASE_ANON_KEY=sb_publishable_DfTB6qME8BkTmHNJ3dCBew_t1NLATEq
|
||||
|
|
@ -536,6 +570,7 @@ SUPABASE_URL=https://supabase.aethex.tech
|
|||
```
|
||||
|
||||
### Discord OAuth
|
||||
|
||||
```
|
||||
DISCORD_CLIENT_ID=578971245454950421
|
||||
DISCORD_CLIENT_SECRET=JKlilGzcTWgfmt2wEqiHO8wpCel5VEji
|
||||
|
|
@ -545,6 +580,7 @@ DISCORD_ADMIN_REGISTER_TOKEN=aethex-link
|
|||
```
|
||||
|
||||
### Roblox OAuth
|
||||
|
||||
```
|
||||
ROBLOX_OAUTH_CLIENT_ID=4727645256213520722
|
||||
ROBLOX_OAUTH_CLIENT_SECRET=RBX-hTAHd1iV-U-JSodk9GDkx0beYrLf00YKdZbWyMPzTWysCsys-UPEvT9ON_qSEeM2
|
||||
|
|
@ -552,11 +588,13 @@ ROBLOX_OAUTH_REDIRECT_URI=https://aethex.dev/roblox-callback
|
|||
```
|
||||
|
||||
### Web3
|
||||
|
||||
```
|
||||
(No env vars needed - signature verification is client-side)
|
||||
```
|
||||
|
||||
### API Base
|
||||
|
||||
```
|
||||
VITE_API_BASE=https://e7c3806a9bfe4bdf9bb8a72a7f0d31cd-324f24a826ec4eb198c1a0eef.fly.dev
|
||||
```
|
||||
|
|
@ -583,21 +621,25 @@ VITE_API_BASE=https://e7c3806a9bfe4bdf9bb8a72a7f0d31cd-324f24a826ec4eb198c1a0eef
|
|||
## 8. WHAT NEEDS WORK ⏳
|
||||
|
||||
1. **CSP Headers for Discord Activity**
|
||||
|
||||
- Status: ⏳ NEEDS FIX
|
||||
- Action: Add to vite.config.ts and vercel.json
|
||||
- Priority: HIGH
|
||||
|
||||
2. **Discord Embedded App SDK (Dual Auth)**
|
||||
|
||||
- Status: ⏳ PARTIALLY DONE
|
||||
- Action: Implement full dual-auth flow in DiscordActivity.tsx
|
||||
- Priority: MEDIUM
|
||||
|
||||
3. **RLS Policy Optimization**
|
||||
|
||||
- Status: ✅ WORKS, CAN OPTIMIZE
|
||||
- Action: Wrap auth.uid() in (select auth.uid()) for performance
|
||||
- Priority: LOW
|
||||
|
||||
4. **GitHub Actions CI/CD**
|
||||
|
||||
- Status: ⏳ NOT IMPLEMENTED
|
||||
- Action: Create .github/workflows/deploy-supabase.yml
|
||||
- Priority: MEDIUM
|
||||
|
|
@ -616,18 +658,18 @@ Frontend:
|
|||
code/client/pages/ - All pages
|
||||
code/client/contexts/ - Auth, Web3, Discord contexts
|
||||
code/client/components/ - All UI components
|
||||
|
||||
|
||||
Backend:
|
||||
code/api/ - All API endpoints
|
||||
code/server/index.ts - Express server + Discord handlers
|
||||
|
||||
|
||||
Database:
|
||||
code/supabase/migrations/ - All SQL migrations
|
||||
|
||||
|
||||
Discord Bot:
|
||||
code/discord-bot/ - All bot code
|
||||
code/discord-bot/commands/ - Slash commands
|
||||
|
||||
|
||||
Documentation:
|
||||
code/docs/ - All guides and documentation
|
||||
```
|
||||
|
|
@ -637,23 +679,27 @@ Documentation:
|
|||
## 10. DEPLOYMENT CHECKLIST
|
||||
|
||||
### Frontend (Vercel)
|
||||
|
||||
- [ ] Environment variables set in Vercel dashboard
|
||||
- [ ] CSP headers configured in vercel.json
|
||||
- [ ] Branch deployments working
|
||||
- [ ] Discord OAuth redirect URI set in Discord portal
|
||||
|
||||
### Backend (Supabase)
|
||||
|
||||
- [ ] All migrations applied
|
||||
- [ ] RLS policies enabled on all tables
|
||||
- [ ] Service role key securely stored
|
||||
|
||||
### Bot (Railway)
|
||||
|
||||
- [ ] Environment variables set
|
||||
- [ ] Bot token valid and bot is online
|
||||
- [ ] Slash commands registered
|
||||
- [ ] Database connection working
|
||||
|
||||
### Discord Developer Portal
|
||||
|
||||
- [ ] OAuth2 redirect URI: https://aethex.dev/api/discord/oauth/callback
|
||||
- [ ] Bot invited to test servers
|
||||
- [ ] Slash commands enabled
|
||||
|
|
|
|||
Loading…
Reference in a new issue