diff --git a/docs/foundation-site-export.json b/docs/foundation-site-export.json new file mode 100644 index 00000000..338e6f14 --- /dev/null +++ b/docs/foundation-site-export.json @@ -0,0 +1,179 @@ +{ + "project": "aethex-forge", + "generated_at": "2025-11-16T00:00:00Z", + "overview": { + "description": "Comprehensive export of the Foundation site: frontend routes, components, server endpoints, Supabase schema references, Discord integration, build and deployment details.", + "root": "/", + "notes": "This file describes site structure, code locations, and deployment guidance. It references files present in the repository under 'code/'." + }, + "frontend": { + "framework": "Vite + React", + "entry": "code/client/main.tsx", + "app_root": "code/client/App.tsx", + "pages_dir": "code/client/pages", + "pages": [ + "code/client/pages/Index.tsx", + "code/client/pages/Login.tsx", + "code/client/pages/DiscordVerify.tsx", + "code/client/pages/Dashboard.tsx", + "code/client/pages/Activity.tsx", + "code/client/pages/Onboarding.tsx", + "code/client/pages/Admin.tsx", + "code/client/pages/404.tsx", + "code/client/pages/About.tsx", + "code/client/pages/creators/CreatorProfile.tsx", + "code/client/pages/docs/DocsOverview.tsx", + "code/client/pages/docs/DocsTutorials.tsx\n "], + "routes_and_expected_urls": { + "/": "Index (code/client/pages/Index.tsx)", + "/login": "Login (code/client/pages/Login.tsx)", + "/dashboard": "Dashboard (code/client/pages/Dashboard.tsx)", + "/activity": "Discord Activity SPA (code/client/pages/Activity.tsx)", + "/onboarding": "Onboarding (code/client/pages/Onboarding.tsx)", + "/profile/:username": "Creator Profile (code/client/pages/creators/CreatorProfile.tsx)", + "/profile/link-discord": "Discord verification (code/client/pages/DiscordVerify.tsx)", + "/docs/*": "Docs pages (code/client/pages/docs/*)", + "subdomain passports (example: mrpiglr.aethex.me)": "Handled by client SubdomainPassport component (code/client/pages/SubdomainPassport.tsx) which fetches API: /api/passport/subdomain-data/:username" + }, + "components_highlights": [ + "code/client/components/Layout.tsx - app layout, header, nav", + "code/client/components/ui/* - shared UI primitives (accordion, alert, toast, loading)", + "code/client/components/passport/PassportSummary.tsx - renders passport summary", + "code/client/components/settings/OAuthConnections.tsx - OAuth providers UI (Discord etc.)", + "code/client/components/admin/AdminDiscordManagement.tsx - admin UI for discord role mappings", + "code/client/components/blog/* and docs components under code/client/components/docs" + ], + "static_assets": "code/public (discord-manifest.json, placeholder.svg, robots.txt, site.webmanifest, etc.)" + }, + "client_integration_points": { + "AuthContext": "code/client/contexts/AuthContext.tsx (central auth state, linkProvider('discord') flow)", + "DiscordActivityContext": "code/client/contexts/DiscordActivityContext.tsx (Activity SDK integration)", + "api_helpers": "code/client/api/* (client-side API wrappers)" + }, + "api_and_server": { + "server_framework": "Express mounted into Vite dev middleware and built as a Node server", + "express_entry": "code/server/index.ts", + "server_build_entry": "code/server/node-build.ts (production entry)", + "server_mount_in_dev": "code/vite.config.ts -> expressPlugin loads createServer() from code/server/index.ts", + "server_routes_summary": { + "/api/passport/subdomain-data/:username": "Returns JSON for creator passport (code/server/index.ts)", + "/api/passport/project-data/:projectSlug": "Returns JSON for project passport (code/server/index.ts)", + "Discord OAuth and linking endpoints (server or api/*):": [ + "code/api/discord/oauth/start.ts - OAuth start redirect", + "code/api/discord/oauth/callback.ts - OAuth callback handler", + "code/api/discord/link.ts - Link via verification code", + "code/api/discord/verify-code.ts - Verify posted code", + "code/api/discord/activity-auth.ts - Activity token verification", + "code/api/discord/sync-roles.ts - Role sync endpoint", + "code/api/discord/admin-register-commands.ts - (admin command registration)" + ], + "Other serverless APIs (Vercel-style) under code/api": "Many endpoints for achievements, profile/ensure, feed, blog, nexus, etc. See code/api/**/*" + }, + "server_notes": "Production server serves dist/spa static files from dist/server and runs the Express app (node dist/server/production.mjs). In dev the Express app is mounted into Vite dev server.", + "server_files": ["code/server/index.ts","code/server/supabase.ts","code/server/node-build.ts"] + }, + "supabase_and_db": { + "primary": "VITE_SUPABASE_URL (https://kmdeisowhtsalsekkzqd.supabase.co) and alias SUPABASE_URL (https://supabase.aethex.tech)", + "service_role": "SUPABASE_SERVICE_ROLE (server-side service role token)", + "migrations_dir": "code/supabase/migrations", + "relevant_migrations": [ + "code/supabase/migrations/20250107_add_discord_integration.sql", + "code/supabase/migrations/202407090001_create_applications.sql", + "... other migrations under code/supabase/migrations" + ], + "important_tables": [ + "user_profiles", + "user_achievements", + "user_interests", + "user_auth_identities", + "discord_links", + "discord_verifications", + "discord_role_mappings", + "applications, invites, other project-specific tables" + ], + "db_access_from_server": "code/api/_supabase.ts (serverless functions) and code/server/supabase.ts (Express server) initialize admin clients using SUPABASE_SERVICE_ROLE" + }, + "discord_integration": { + "bot_code": "code/discord-bot/bot.js and commands under code/discord-bot/commands/*.js", + "oauth": { + "start": "code/api/discord/oauth/start.ts", + "callback": "code/api/discord/oauth/callback.ts", + "redirect_uri_env": "DISCORD_REDIRECT_URI (set to production callback URL)" + }, + "activity": { + "manifest": "code/public/discord-manifest.json", + "activity_auth_endpoint": "code/api/discord/activity-auth.ts", + "client_integration": "code/client/contexts/DiscordActivityContext.tsx and code/client/pages/Activity.tsx" + }, + "linking_flow": "user clicks 'Link Discord' -> linkProvider('discord') -> /api/discord/oauth/start -> OAuth -> /api/discord/oauth/callback -> backend saves discord_link (discord_links table) -> triggers role sync", + "slash_commands": "registered via discord-bot scripts or admin API (code/discord-bot/scripts/register-commands.js / code/api/discord/admin-register-commands.ts)", + "health_checks": "code/client/lib/discord-bot-status.ts polls bot health endpoints (bot health API located in code/server/index.ts or code/api/discord/bot-health.ts)" + }, + "design_and_layout": { + "design_system": "Tailwind CSS + Lucide icons + Radix UI primitives (see dependencies)", + "global_styles": "code/client/global.css", + "layout_component": "code/client/components/Layout.tsx", + "passport_ui": "code/client/components/passport/PassportSummary.tsx", + "theme_and_switcher": "code/client/components/ThemeToggle and ArmSwitcher in code/client/components/ArmSwitcher.tsx", + "ui_primitives": "code/client/components/ui/* (accordion, alert, toast, loading screen)" + }, + "build_and_scripts": { + "dev": "npm run dev -> vite (code/vite.config.ts mounts Express in dev)", + "build_flow": "npm run build -> build:api (node build-api.js), build:client (vite build), build:server (vite build --config vite.config.server.ts)", + "start_production": "npm start -> node dist/server/production.mjs", + "docker": "code/Dockerfile (added for Railway); builds and runs the production server exposing PORT (3000)", + "important_files": ["code/package.json","code/vite.config.server.ts","code/vite.config.ts","code/build-api.js","code/Dockerfile"] + }, + "deployment_and_hosts": { + "current_hosts": { + "vercel": "Frontend + serverless functions (code/api/*) can be deployed to Vercel", + "fly_io": "Previously used to host Express server; domain example given in conversation", + "railway": "Configured (code/railway.json + Dockerfile) as recommended unified host for Express + Bot + Frontend" + }, + "dns_notes": "Subdomain passports require wildcard DNS (*.aethex.me) pointing to the host running Express server. If Express is on Railway/Fly, update DNS accordingly. Vercel cannot serve arbitrary wildcard subdomain server routes unless serverless functions handle them.", + "recommended_setup": "Keep frontend on Vercel if desired; deploy Express + Discord bot to Railway or Fly; point wildcard DNS to that host. Alternatively deploy everything to Railway for single-host simplicity." + }, + "environment_variables": { + "required_keys": [ + "VITE_SUPABASE_URL", + "VITE_SUPABASE_ANON_KEY", + "SUPABASE_SERVICE_ROLE", + "SUPABASE_URL", + "DISCORD_CLIENT_ID", + "DISCORD_CLIENT_SECRET", + "DISCORD_BOT_TOKEN", + "DISCORD_PUBLIC_KEY", + "DISCORD_REDIRECT_URI", + "VITE_API_BASE", + "SMTP_HOST", + "SMTP_PORT", + "SMTP_USER", + "SMTP_PASSWORD", + "VITE_GHOST_API_URL", + "GHOST_ADMIN_API_KEY", + "FOURTHWALL_API_EMAIL", + "FOURTHWALL_API_PASSWORD" + ], + "notes": "Do not commit secrets to source. Use Railway/Vercel environment settings or Vault. Many variables are present in the project environment already; ensure production values are set in your deployment host." + }, + "export_instructions": { + "purpose": "This file is a machine-readable site map and operational guide. Use as baseline for exporting docs or generating human-friendly markdown/zip exports.", + "how_to_export_code": [ + "1. Push latest branch to remote (use Push Code in UI)", + "2. Build artifacts (npm run build) locally to verify", + "3. Package dist/spa and dist/server for deployment", + "4. Ensure env vars set on target host", + "5. Update DNS to point wildcard domains to host running Express" + ] + }, + "appendix": { + "key_files_index": { + "frontend": ["code/client/App.tsx","code/client/main.tsx","code/client/global.css","code/client/pages/*","code/client/components/*","code/client/contexts/*"], + "api": ["code/api/* (serverless functions)","code/api/discord/*","code/api/passport/*","code/api/profile/ensure.ts"], + "server": ["code/server/index.ts","code/server/supabase.ts","code/server/node-build.ts"], + "discord": ["code/discord-bot/bot.js","code/discord-bot/commands/*"], + "migrations": ["code/supabase/migrations/*"] + }, + "contact": "Repository owner / admin (you)" + } +} diff --git a/package-lock.json b/package-lock.json index d93b1fc4..0893779a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,8 +12,10 @@ "@supabase/supabase-js": "^2.53.0", "@vercel/analytics": "^1.5.0", "dotenv": "^17.2.0", + "ethers": "^6.13.0", "express": "^4.18.2", "nodemailer": "^7.0.10", + "stripe": "^15.12.0", "zod": "^3.23.8" }, "devDependencies": { @@ -93,6 +95,12 @@ "vitest": "^3.1.4" } }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -1785,6 +1793,30 @@ "three": ">= 0.159.0" } }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -5310,7 +5342,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.5.5", + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -5907,6 +5941,12 @@ "node": ">=0.4.0" } }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "license": "MIT" + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -8098,6 +8138,55 @@ "node": ">= 0.6" } }, + "node_modules/ethers": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.15.0.tgz", + "integrity": "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "22.7.5", + "aes-js": "4.0.0-beta.5", + "tslib": "2.7.0", + "ws": "8.17.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "dev": true, @@ -11172,6 +11261,19 @@ "node": ">=0.10.0" } }, + "node_modules/stripe": { + "version": "15.12.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-15.12.0.tgz", + "integrity": "sha512-slTbYS1WhRJXVB8YXU8fgHizkUrM9KJyrw4Dd8pLEwzKHYyQTIE46EePC2MVbSDZdE24o1GdNtzmJV4PrPpmJA==", + "license": "MIT", + "dependencies": { + "@types/node": ">=8.1.0", + "qs": "^6.11.0" + }, + "engines": { + "node": ">=12.*" + } + }, "node_modules/strnum": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz", @@ -11668,7 +11770,6 @@ }, "node_modules/tslib": { "version": "2.7.0", - "dev": true, "license": "0BSD" }, "node_modules/tsx": {