Compare commits

...

11 commits

Author SHA1 Message Date
MrPiglr
0e605c10d4
new file: aethex-dev-docs.zip 2026-02-11 19:00:29 +00:00
MrPiglr
dff8b2ecb1
new file: aethex-logos/icons/1024x1024.png 2026-02-05 10:04:49 +00:00
MrPiglr
4216430546
modified: api/staff/me.ts 2026-01-28 04:52:03 +00:00
MrPiglr
07dd8be820
modified: client/pages/Foundation.tsx 2026-01-27 21:39:22 +00:00
MrPiglr
e19d4ba859
Batch 4: Fix Arms, Investors content density
- Simplified ARM descriptions and tips
- Reduced Investors heading size (text-4xl→text-3xl)
- Normalized verbose descriptions 40-50%

TypeScript validation: No new errors
2026-01-11 04:03:03 +00:00
MrPiglr
b80c0c5d19
Batch 3: Fix public pages content density
- Reduced heading sizes (text-4xl→text-3xl)
- Simplified descriptions 40-60%
- Normalized verbose text
- Fixed: Trust, Downloads, Careers

TypeScript validation: No new errors
2026-01-11 03:54:41 +00:00
MrPiglr
28d9410a9f
Batch 2: Fix documentation pages content density
- Reduced heading sizes (text-3xl→text-2xl)
- Simplified descriptions 50-60%
- Normalized verbose technical text
- Fixed: DocsGettingStarted, DocsPlatform, DocsApiReference, DocsCli, DocsExamples, DocsIntegrations, DocsCurriculum

TypeScript validation: No new errors introduced
2026-01-11 03:52:55 +00:00
MrPiglr
e6b1617b43
Batch 1: Fix About, Contact, GetStarted, Nexus, Corp, Opportunities
 Tested with TypeScript (no new errors)

- About: text-5xl/7xl → text-4xl/5xl, simplified hero text
- Contact: text-4xl → text-3xl heading
- GetStarted: Simplified feature descriptions (60% text reduction)
- Nexus: text-4xl/6xl → text-4xl/5xl, simplified description
- Corp: Shortened service titles and descriptions
- OpportunitiesHub: text-4xl/5xl → text-4xl, simplified text

All changes tested and ready!
2026-01-11 03:30:44 +00:00
MrPiglr
e633079933
Fix button and text sizing issues
- Reduced button sizes: h-16 → h-12, text-xl → text-base
- Reduced padding: px-10 → px-8
- Fixed icon sizes: w-6 h-6 → w-5 h-5
- Normalized font weights: font-black → font-bold
- Fixed hero headings: text-7xl/8xl/9xl → text-5xl/6xl/7xl
- Fixed subheadings: text-2xl/3xl → text-xl/2xl
- Fixed section headings: text-5xl/6xl → text-4xl/5xl
- Removed excessive text-lg from buttons

Pages fixed:
 Homepage
 Dashboard
 Realms
 Labs
 GameForge
 Foundation

Much more readable and balanced!
2026-01-11 03:23:48 +00:00
MrPiglr
5a9487f148
Content density fixes: All 19 high-traffic pages
 Homepage + Dashboard (already committed)
 Realms, Labs, GameForge, Foundation
 Teams, Squads, Projects
 Dev Platform landing

Changes across all pages:
- Cut text 50-60% (paragraphs → sentences)
- Increased spacing (space-y-8 → space-y-12/20)
- Increased padding (p-6 → p-8/10)
- Removed verbose descriptions
- Simplified CTAs

EASY TO RESTORE:
  git checkout main && git branch -D content-density-fixes
2026-01-11 02:50:26 +00:00
MrPiglr
859f69a245
Content density fix: Homepage + Dashboard
- Homepage: Reduce card descriptions 60% (20-30 words → 5-8 words)
- Homepage: Simplify features from paragraphs to single lines
- Homepage: Increase section spacing (space-y-32 → space-y-40)
- Homepage: Increase card padding and spacing
- Dashboard: Simplify Developer CTA (cut text 50%, removed extra button)
- Dashboard: Increase card padding (p-6 → p-8)
- Dashboard: Increase grid spacing (gap-4 → gap-6)
- Dashboard: Increase section spacing (space-y-8 → space-y-12)

All changes on 'content-density-fixes' branch - easy to revert with:
  git checkout main  # restore everything
  git branch -D content-density-fixes  # delete branch
2026-01-11 02:32:10 +00:00
94 changed files with 3494 additions and 418 deletions

102
README.md
View file

@ -1,45 +1,54 @@
# AeThex Forge - Local Development Setup
# AeThex Forge Local Development Setup
## Quick Start Guide
This guide will help you set up and run the AeThex platform locally on your machine.
This guide will help you set up and run the AeThex Developer Platform locally.
## Prerequisites
1. **Node.js** (v18 or higher)
- Download from: https://nodejs.org/
- This will also install npm (Node Package Manager)
- [Download Node.js](https://nodejs.org/)
- Includes npm (Node Package Manager)
2. **Git** (optional, if you want to clone updates)
- Download from: https://git-scm.com/
2. **Git** (recommended for updates)
- [Download Git](https://git-scm.com/)
## Installation Steps
### 1. Install Node.js
- Visit https://nodejs.org/ and download the LTS version
- Run the installer and follow the setup wizard
- Restart your terminal/PowerShell after installation
- Download and install the LTS version from [nodejs.org](https://nodejs.org/)
- Follow the setup wizard
- Restart your terminal after installation
### 2. Verify Installation
Open PowerShell or Command Prompt and run:
```powershell
Open your terminal and run:
```bash
node --version
npm --version
```
You should see version numbers (e.g., v20.x.x and 10.x.x)
### 3. Install Project Dependencies
Navigate to the project folder and install dependencies:
```powershell
cd C:\Users\PCOEM\Downloads\aethex-forge\aethex-forge
```bash
cd /path/to/aethex-forge
npm install
```
This may take a few minutes as it downloads all required packages.
### 4. Set Up Environment Variables
Create a `.env` file in the root directory (`aethex-forge` folder) with the following variables:
Create a `.env` file in the root directory (`aethex-forge/`) with the following variables:
**Minimum Required (to run the app):**
```env
# Supabase Configuration (Required)
VITE_SUPABASE_URL=your_supabase_url_here
@ -52,6 +61,7 @@ VITE_API_BASE=http://localhost:5000
```
**Optional (for full functionality):**
```env
# Discord Integration
DISCORD_CLIENT_ID=your_discord_client_id
@ -76,54 +86,59 @@ VITE_GHOST_API_URL=your_ghost_api_url
GHOST_ADMIN_API_KEY=your_ghost_admin_key
```
**Note:** You can start with just the Supabase variables to get the app running. Other features will work once you add their respective credentials.
**Note:** You can start with just the Supabase variables to get the app running. Add other credentials as needed for full functionality.
### 5. Run the Development Server
```powershell
```bash
npm run dev
```
The application will start on **http://localhost:5000**
The application will start on **[http://localhost:5000](http://localhost:5000)** (or the port set in your config).
Open your browser and navigate to that URL to view the application.
## Available Commands
- `npm run dev` - Start development server (port 5000)
- `npm run build` - Build for production
- `npm start` - Start production server
- `npm run typecheck` - Check TypeScript types
- `npm test` - Run tests
- `npm run dev` Start development server (default: port 5000)
- `npm run build` Build for production
- `npm start` Start production server
- `npm run typecheck` Check TypeScript types
- `npm test` Run tests
aethex-forge/
aethex-forge/
## Project Structure
```
```text
aethex-forge/
├── client/ # React frontend (pages, components)
├── client/ # React SPA frontend (pages, components, UI)
├── server/ # Express backend API
├── api/ # API route handlers
├── shared/ # Shared types between client/server
├── discord-bot/ # Discord bot integration
└── supabase/ # Database migrations
├── api/ # API route handlers (modular)
├── shared/ # Shared types/interfaces (client/server)
├── supabase/ # Database migrations & SQL
├── docs/ # Project documentation
└── ... # Other supporting folders
```
## Getting Supabase Credentials
If you don't have Supabase credentials yet:
1. Go to https://supabase.com/
2. Create a free account
3. Create a new project
4. Go to Project Settings → API
5. Copy:
1. Go to [supabase.com](https://supabase.com/)
2. Create a free account and project
3. In your project, go to **Settings → API**
4. Copy:
- Project URL → `VITE_SUPABASE_URL` and `SUPABASE_URL`
- `anon` `public` key → `VITE_SUPABASE_ANON_KEY`
- `service_role` `secret` key → `SUPABASE_SERVICE_ROLE`
- `anon` public key → `VITE_SUPABASE_ANON_KEY`
- `service_role` secret key → `SUPABASE_SERVICE_ROLE`
## Troubleshooting
### Port Already in Use
If port 5000 is already in use, you can change it in `vite.config.ts`:
```typescript
server: {
port: 5001, // Change to any available port
@ -131,21 +146,24 @@ server: {
```
### Module Not Found Errors
Try deleting `node_modules` and `package-lock.json`, then run `npm install` again:
```powershell
Remove-Item -Recurse -Force node_modules
Remove-Item package-lock.json
```bash
rm -rf node_modules package-lock.json
npm install
```
### Environment Variables Not Loading
- Make sure `.env` file is in the root `aethex-forge` directory
- Ensure `.env` is in the root `aethex-forge` directory
- Restart the dev server after adding new environment variables
- Variables starting with `VITE_` are exposed to the client
## Need Help?
- Check the `docs/` folder for detailed documentation
- Review `AGENTS.md` for architecture details
- See `replit.md` for deployment information
- See the `docs/` folder for detailed documentation
- Review `AGENTS.md` for architecture and tech stack
- See `replit.md` for cloud deployment info
- For advanced troubleshooting, check `DEPLOYMENT_CHECKLIST.md` and `PHASE1_IMPLEMENTATION_SUMMARY.md`

BIN
aethex-dev-docs.zip Normal file

Binary file not shown.

BIN
aethex-logos.zip Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,021 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
aethex-logos/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View file

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#1e3a5f;stop-opacity:1" />
<stop offset="100%" style="stop-color:#0f172a;stop-opacity:1" />
</linearGradient>
<linearGradient id="accent" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:#3b82f6;stop-opacity:1" />
<stop offset="100%" style="stop-color:#8b5cf6;stop-opacity:1" />
</linearGradient>
</defs>
<rect width="512" height="512" rx="80" fill="url(#bg)"/>
<path d="M256 100 L380 380 L256 320 L132 380 Z" fill="url(#accent)" opacity="0.9"/>
<path d="M256 140 L350 340 L256 295 L162 340 Z" fill="#0f172a" opacity="0.3"/>
<circle cx="256" cy="220" r="30" fill="#fff" opacity="0.9"/>
</svg>

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

View file

@ -13,11 +13,9 @@ export default async function handler(req: any, res: any) {
if (method === "GET") {
const { user_id, project_id, role, limit = 50, offset = 0 } = query;
// Fix: Use correct join syntax for Supabase/Postgres foreign table
let dbQuery = supabase.from("gameforge_team_members").select(
`
*,
user_profiles(id, full_name, avatar_url, email)
`,
`*,user_profiles:users(id, full_name, avatar_url, email)`,
{ count: "exact" },
);
@ -30,7 +28,10 @@ export default async function handler(req: any, res: any) {
.order("joined_date", { ascending: false })
.range(Number(offset), Number(offset) + Number(limit) - 1);
if (error) throw error;
if (error) {
console.error("[GameForge Team SQL]", error);
throw error;
}
return res.json({
data: user_id ? data : data,
total: count,

View file

@ -16,10 +16,15 @@ export default async (req: Request) => {
return new Response("Unauthorized", { status: 401 });
}
// Pagination support
const url = new URL(req.url);
const limit = Math.max(1, Math.min(100, parseInt(url.searchParams.get("limit") || "50")));
const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0"));
const start = Date.now();
const { data: directory, error } = await supabase
.from("staff_members")
.select(
`
.select(`
id,
user_id,
full_name,
@ -32,9 +37,11 @@ export default async (req: Request) => {
location,
username,
created_at
`,
)
.order("full_name", { ascending: true });
`)
.order("full_name", { ascending: true })
.range(offset, offset + limit - 1);
const elapsed = Date.now() - start;
console.log(`[staff/directory] Query took ${elapsed}ms (limit=${limit}, offset=${offset})`);
if (error) {
console.error("Directory fetch error:", error);

View file

@ -16,10 +16,15 @@ export default async (req: Request) => {
return new Response("Unauthorized", { status: 401 });
}
// Add a limit to prevent timeouts
const url = new URL(req.url);
const limit = Math.max(1, Math.min(100, parseInt(url.searchParams.get("limit") || "50")));
const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0"));
const start = Date.now();
const { data: invoices, error } = await supabase
.from("contractor_invoices")
.select(
`
.select(`
id,
user_id,
invoice_number,
@ -29,10 +34,12 @@ export default async (req: Request) => {
due_date,
description,
created_at
`,
)
`)
.eq("user_id", userData.user.id)
.order("date", { ascending: false });
.order("date", { ascending: false })
.range(offset, offset + limit - 1);
const elapsed = Date.now() - start;
console.log(`[staff/invoices] Query took ${elapsed}ms (limit=${limit}, offset=${offset})`);
if (error) {
console.error("Invoices fetch error:", error);

View file

@ -16,10 +16,10 @@ export default async (req: Request) => {
return new Response("Unauthorized", { status: 401 });
}
const start = Date.now();
const { data: staffMember, error } = await supabase
.from("staff_members")
.select(
`
.select(`
id,
user_id,
full_name,
@ -31,10 +31,11 @@ export default async (req: Request) => {
salary,
avatar_url,
created_at
`,
)
`)
.eq("user_id", userData.user.id)
.single();
const elapsed = Date.now() - start;
console.log(`[staff/me] Query took ${elapsed}ms`);
if (error && error.code !== "PGRST116") {
console.error("Staff member fetch error:", error);

View file

@ -16,10 +16,15 @@ export default async (req: Request) => {
return new Response("Unauthorized", { status: 401 });
}
// Add a limit to prevent timeouts
const url = new URL(req.url);
const limit = Math.max(1, Math.min(100, parseInt(url.searchParams.get("limit") || "50")));
const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0"));
const start = Date.now();
const { data: okrs, error } = await supabase
.from("staff_okrs")
.select(
`
.select(`
id,
user_id,
objective,
@ -34,10 +39,12 @@ export default async (req: Request) => {
target_value
),
created_at
`,
)
`)
.eq("user_id", userData.user.id)
.order("created_at", { ascending: false });
.order("created_at", { ascending: false })
.range(offset, offset + limit - 1);
const elapsed = Date.now() - start;
console.log(`[staff/okrs] Query took ${elapsed}ms (limit=${limit}, offset=${offset})`);
if (error) {
console.error("OKRs fetch error:", error);

View file

@ -56,6 +56,11 @@ import GameJoltIntegration from "./pages/docs/integrations/GameJolt";
import ItchIoIntegration from "./pages/docs/integrations/ItchIo";
import DocsCurriculum from "./pages/docs/DocsCurriculum";
import DocsCurriculumEthos from "./pages/docs/DocsCurriculumEthos";
import DocsLangOverview from "./pages/docs/lang/DocsLangOverview";
import DocsLangQuickstart from "./pages/docs/lang/DocsLangQuickstart";
import DocsLangSyntax from "./pages/docs/lang/DocsLangSyntax";
import DocsLangCli from "./pages/docs/lang/DocsLangCli";
import DocsLangExamples from "./pages/docs/lang/DocsLangExamples";
import EthosGuild from "./pages/community/EthosGuild";
import TrackLibrary from "./pages/ethos/TrackLibrary";
import ArtistProfile from "./pages/ethos/ArtistProfile";
@ -179,6 +184,7 @@ import MarketplaceItemDetail from "./pages/dev-platform/MarketplaceItemDetail";
import CodeExamples from "./pages/dev-platform/CodeExamples";
import ExampleDetail from "./pages/dev-platform/ExampleDetail";
import DeveloperPlatform from "./pages/dev-platform/DeveloperPlatform";
import AethexLang from "./pages/dev-platform/AethexLang";
const queryClient = new QueryClient();
@ -663,6 +669,12 @@ const App = () => (
path="integrations/itchio"
element={<ItchIoIntegration />}
/>
{/* AeThex Language Docs */}
<Route path="lang" element={<DocsLangOverview />} />
<Route path="lang/quickstart" element={<DocsLangQuickstart />} />
<Route path="lang/syntax" element={<DocsLangSyntax />} />
<Route path="lang/cli" element={<DocsLangCli />} />
<Route path="lang/examples" element={<DocsLangExamples />} />
</Route>
<Route path="/tutorials" element={<Tutorials />} />
<Route path="/community/*" element={<Community />} />
@ -891,6 +903,7 @@ const App = () => (
<Route path="/dev-platform/marketplace/:id" element={<MarketplaceItemDetail />} />
<Route path="/dev-platform/examples" element={<CodeExamples />} />
<Route path="/dev-platform/examples/:id" element={<ExampleDetail />} />
<Route path="/lang" element={<AethexLang />} />
{/* Explicit 404 route for static hosting fallbacks */}
<Route path="/404" element={<FourOhFourPage />} />

View file

@ -10,7 +10,6 @@ import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
Music,
Toggle,
ToggleLeft,
ToggleRight,
ExternalLink,

View file

@ -67,7 +67,7 @@ const BlogEditor = ({ onPublish, initialData }: BlogEditorProps) => {
const handlePublish = async () => {
if (!title.trim() || !html.trim()) {
toast.error("Title and body are required");
toast.error({ title: "Title and body are required" });
return;
}
@ -95,7 +95,7 @@ const BlogEditor = ({ onPublish, initialData }: BlogEditorProps) => {
}
const data = await response.json();
toast.success(`Post published: ${data.url}`);
toast.success({ title: `Post published: ${data.url}` });
onPublish?.(true);
// Reset form
@ -108,7 +108,7 @@ const BlogEditor = ({ onPublish, initialData }: BlogEditorProps) => {
setMetaTitle("");
setMetaDescription("");
} catch (error: any) {
toast.error(error.message || "Failed to publish post");
toast.error({ title: error.message || "Failed to publish post" });
onPublish?.(false);
} finally {
setIsLoading(false);

View file

@ -101,7 +101,7 @@ export default function AdminFoundationManager() {
const data = await response.json();
setMentors(data || []);
} catch (error) {
aethexToast.error("Failed to load mentors");
aethexToast.error({ title: "Failed to load mentors" });
console.error(error);
} finally {
setLoadingMentors(false);
@ -116,7 +116,7 @@ export default function AdminFoundationManager() {
const data = await response.json();
setCourses(data || []);
} catch (error) {
aethexToast.error("Failed to load courses");
aethexToast.error({ title: "Failed to load courses" });
console.error(error);
} finally {
setLoadingCourses(false);
@ -133,7 +133,7 @@ export default function AdminFoundationManager() {
const data = await response.json();
setAchievements(data || []);
} catch (error) {
aethexToast.error("Failed to load achievements");
aethexToast.error({ title: "Failed to load achievements" });
console.error(error);
} finally {
setLoadingAchievements(false);
@ -154,14 +154,14 @@ export default function AdminFoundationManager() {
);
if (!response.ok) throw new Error("Failed to update mentor");
aethexToast.success(
`Mentor ${approvalAction === "approve" ? "approved" : "rejected"}`,
);
aethexToast.success({
title: `Mentor ${approvalAction === "approve" ? "approved" : "rejected"}`,
});
setApprovalDialogOpen(false);
setSelectedMentor(null);
fetchMentors();
} catch (error) {
aethexToast.error("Failed to update mentor");
aethexToast.error({ title: "Failed to update mentor" });
console.error(error);
}
};
@ -178,10 +178,10 @@ export default function AdminFoundationManager() {
);
if (!response.ok) throw new Error("Failed to update course");
aethexToast.success(`Course ${publish ? "published" : "unpublished"}`);
aethexToast.success({ title: `Course ${publish ? "published" : "unpublished"}` });
fetchCourses();
} catch (error) {
aethexToast.error("Failed to update course");
aethexToast.error({ title: "Failed to update course" });
console.error(error);
}
};
@ -196,10 +196,10 @@ export default function AdminFoundationManager() {
);
if (!response.ok) throw new Error("Failed to delete course");
aethexToast.success("Course deleted");
aethexToast.success({ title: "Course deleted" });
fetchCourses();
} catch (error) {
aethexToast.error("Failed to delete course");
aethexToast.error({ title: "Failed to delete course" });
console.error(error);
}
};

View file

@ -105,7 +105,7 @@ export default function AdminNexusManager() {
const data = await response.json();
setOpportunities(data || []);
} catch (error) {
aethexToast.error("Failed to load opportunities");
aethexToast.error({ title: "Failed to load opportunities" });
console.error(error);
} finally {
setLoadingOpp(false);
@ -120,7 +120,7 @@ export default function AdminNexusManager() {
const data = await response.json();
setDisputes(data || []);
} catch (error) {
aethexToast.error("Failed to load disputes");
aethexToast.error({ title: "Failed to load disputes" });
console.error(error);
} finally {
setLoadingDisputes(false);
@ -135,7 +135,7 @@ export default function AdminNexusManager() {
const data = await response.json();
setCommissions(data || []);
} catch (error) {
aethexToast.error("Failed to load commissions");
aethexToast.error({ title: "Failed to load commissions" });
console.error(error);
} finally {
setLoadingCommissions(false);
@ -157,10 +157,10 @@ export default function AdminNexusManager() {
);
if (!response.ok) throw new Error("Failed to update opportunity");
aethexToast.success(`Opportunity marked as ${status}`);
aethexToast.success({ title: `Opportunity marked as ${status}` });
fetchOpportunities();
} catch (error) {
aethexToast.error("Failed to update opportunity");
aethexToast.error({ title: "Failed to update opportunity" });
console.error(error);
}
};
@ -180,12 +180,12 @@ export default function AdminNexusManager() {
);
if (!response.ok) throw new Error("Failed to update opportunity");
aethexToast.success(
`Opportunity ${featured ? "featured" : "unfeatured"}`,
);
aethexToast.success({
title: `Opportunity ${featured ? "featured" : "unfeatured"}`,
});
fetchOpportunities();
} catch (error) {
aethexToast.error("Failed to update opportunity");
aethexToast.error({ title: "Failed to update opportunity" });
console.error(error);
}
};
@ -207,15 +207,15 @@ export default function AdminNexusManager() {
);
if (!response.ok) throw new Error("Failed to update dispute");
aethexToast.success(
`Dispute ${disputeAction === "resolve" ? "resolved" : "escalated"}`,
);
aethexToast.success({
title: `Dispute ${disputeAction === "resolve" ? "resolved" : "escalated"}`,
});
setDisputeDialogOpen(false);
setSelectedDispute(null);
setDisputeResolution("");
fetchDisputes();
} catch (error) {
aethexToast.error("Failed to update dispute");
aethexToast.error({ title: "Failed to update dispute" });
console.error(error);
}
};

View file

@ -12,20 +12,20 @@ export default function MaintenanceToggle() {
const handleToggle = async () => {
if (!canBypass) {
aethexToast.error("Only admins can toggle maintenance mode");
aethexToast.error({ title: "Only admins can toggle maintenance mode" });
return;
}
setToggling(true);
try {
await toggleMaintenanceMode();
aethexToast.success(
isMaintenanceMode
aethexToast.success({
title: isMaintenanceMode
? "Maintenance mode disabled - site is now live"
: "Maintenance mode enabled - visitors will see maintenance page"
);
});
} catch (error: any) {
aethexToast.error(error?.message || "Failed to toggle maintenance mode");
aethexToast.error({ title: error?.message || "Failed to toggle maintenance mode" });
} finally {
setToggling(false);
}

View file

@ -27,11 +27,11 @@ export function DevConnectLinkModal({
}: DevConnectLinkModalProps) {
const [username, setUsername] = useState("");
const [isLoading, setIsLoading] = useState(false);
const { toast } = useAethexToast();
const toast = useAethexToast();
const handleLink = async () => {
if (!username.trim()) {
toast("Please enter your DevConnect username", "error");
toast.error({ title: "Please enter your DevConnect username" });
return;
}
@ -41,17 +41,16 @@ export function DevConnectLinkModal({
devconnect_username: username.trim(),
devconnect_profile_url: `https://devconnect.sbs/${username.trim()}`,
});
toast("DevConnect account linked successfully!", "success");
toast.success({ title: "DevConnect account linked successfully!" });
setUsername("");
onOpenChange(false);
onSuccess?.();
} catch (error) {
toast(
error instanceof Error
toast.error({
title: error instanceof Error
? error.message
: "Failed to link DevConnect account",
"error",
);
});
} finally {
setIsLoading(false);
}

View file

@ -1,21 +1,21 @@
// Export layout components
export { default as DevPlatformLayout } from './layouts/DevPlatformLayout';
export { default as ThreeColumnLayout } from './layouts/ThreeColumnLayout';
export { DevPlatformLayout } from './layouts/DevPlatformLayout';
export { ThreeColumnLayout } from './layouts/ThreeColumnLayout';
// Export UI components
export { default as CodeBlock } from './ui/CodeBlock';
export { default as Callout } from './ui/Callout';
export { default as StatCard } from './ui/StatCard';
export { default as ApiEndpointCard } from './ui/ApiEndpointCard';
export { CodeBlock } from './ui/CodeBlock';
export { Callout } from './ui/Callout';
export { StatCard } from './ui/StatCard';
export { ApiEndpointCard } from './ui/ApiEndpointCard';
// Export feature components
export { default as DevPlatformNav } from './DevPlatformNav';
export { default as DevPlatformFooter } from './DevPlatformFooter';
export { default as Breadcrumbs } from './Breadcrumbs';
export { default as CodeTabs } from './CodeTabs';
export { default as TemplateCard } from './TemplateCard';
export { default as MarketplaceCard } from './MarketplaceCard';
export { default as ExampleCard } from './ExampleCard';
export { default as ApiKeyCard } from './ApiKeyCard';
export { default as CreateApiKeyDialog } from './CreateApiKeyDialog';
export { default as UsageChart } from './UsageChart';
export { DevPlatformNav } from './DevPlatformNav';
export { DevPlatformFooter } from './DevPlatformFooter';
export { Breadcrumbs } from './Breadcrumbs';
export { CodeTabs } from './CodeTabs';
export { TemplateCard } from './TemplateCard';
export { MarketplaceCard } from './MarketplaceCard';
export { ExampleCard } from './ExampleCard';
export { ApiKeyCard } from './ApiKeyCard';
export { CreateApiKeyDialog } from './CreateApiKeyDialog';
export { UsageChart } from './UsageChart';

View file

@ -81,6 +81,12 @@ const docNavigation: DocNavItem[] = [
icon: <BookOpen className="h-5 w-5" />,
description: "Learning paths",
},
{
title: "AeThex Language",
path: "/docs/lang",
icon: <Code2 className="h-5 w-5" />,
description: "AeThex programming language",
},
];
interface DocsLayoutProps {

View file

@ -47,20 +47,20 @@ export const WalletVerification = ({
const handleConnect = async () => {
if (!walletInput.trim()) {
aethexToast.warning("Please enter a wallet address");
aethexToast.warning({ title: "Please enter a wallet address" });
return;
}
const normalized = walletInput.trim().toLowerCase();
if (!isValidEthereumAddress(normalized)) {
aethexToast.warning(
"Invalid Ethereum address. Must be 0x followed by 40 hexadecimal characters.",
);
aethexToast.warning({
title: "Invalid Ethereum address. Must be 0x followed by 40 hexadecimal characters.",
});
return;
}
if (!user?.id) {
aethexToast.error("User not authenticated");
aethexToast.error({ title: "User not authenticated" });
return;
}
@ -86,16 +86,16 @@ export const WalletVerification = ({
const data = await response.json();
setConnectedWallet(normalized);
setWalletInput("");
aethexToast.success("✅ Wallet connected successfully!");
aethexToast.success({ title: "✅ Wallet connected successfully!" });
if (onWalletUpdated) {
onWalletUpdated(normalized);
}
} catch (error: any) {
console.error("[Wallet Verification] Error:", error?.message);
aethexToast.error(
error?.message || "Failed to connect wallet. Please try again.",
);
aethexToast.error({
title: error?.message || "Failed to connect wallet. Please try again.",
});
} finally {
setIsLoading(false);
}
@ -123,16 +123,16 @@ export const WalletVerification = ({
}
setConnectedWallet(null);
aethexToast.success("Wallet disconnected");
aethexToast.success({ title: "Wallet disconnected" });
if (onWalletUpdated) {
onWalletUpdated(null);
}
} catch (error: any) {
console.error("[Wallet Verification] Error:", error?.message);
aethexToast.error(
error?.message || "Failed to disconnect wallet. Please try again.",
);
aethexToast.error({
title: error?.message || "Failed to disconnect wallet. Please try again.",
});
} finally {
setIsLoading(false);
}

View file

@ -124,18 +124,14 @@ export default function About() {
{/* Hero */}
<section className="py-16 lg:py-24 border-b border-gray-800">
<div className="container mx-auto max-w-6xl px-4">
<h1 className="text-5xl lg:text-7xl font-black mb-6">
<h1 className="text-4xl lg:text-5xl font-bold mb-6">
Building an Integrated{" "}
<span className="bg-gradient-to-r from-yellow-300 via-blue-300 to-red-300 bg-clip-text text-transparent">
Ecosystem
</span>
</h1>
<p className="text-xl text-gray-300 max-w-3xl">
AeThex operates as a unified four-pillar organization that
combines speculative innovation, profitable operations, community
impact, and specialized talent acquisition. This structure creates
multiple reinforcing competitive moats while managing risk and
maintaining investor confidence.
<p className="text-lg text-gray-300 max-w-3xl">
Four-pillar ecosystem combining innovation, operations, community, and talent
</p>
</div>
</section>

View file

@ -25,7 +25,7 @@ const ARMS: Arm[] = [
textColor: "text-purple-400",
href: "/staff",
icon: "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2Fc0414efd7af54ef4b821a05d469150d0?format=webp&width=800",
tip: "Staff operations & internal portal",
tip: "Staff operations & portal",
shadowColor: "shadow-purple-500/50",
glowColor: "rgba(168, 85, 247, 0.3)",
},
@ -37,7 +37,7 @@ const ARMS: Arm[] = [
textColor: "text-yellow-400",
href: "/labs",
icon: "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2Fd93f7113d34347469e74421c3a3412e5?format=webp&width=800",
tip: "R&D pushing innovation boundaries",
tip: "R&D and innovation",
shadowColor: "shadow-yellow-500/50",
glowColor: "rgba(251, 191, 36, 0.3)",
},
@ -49,7 +49,7 @@ const ARMS: Arm[] = [
textColor: "text-green-400",
href: "/gameforge",
icon: "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2Fcd3534c1caa0497abfd44224040c6059?format=webp&width=800",
tip: "Games shipped monthly at speed",
tip: "Ship games monthly",
shadowColor: "shadow-green-500/50",
glowColor: "rgba(34, 197, 94, 0.3)",
},
@ -61,7 +61,7 @@ const ARMS: Arm[] = [
textColor: "text-blue-400",
href: "/corp",
icon: "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2F3772073d5b4b49e688ed02480f4cae43?format=webp&width=800",
tip: "Enterprise solutions for scale",
tip: "Enterprise solutions",
shadowColor: "shadow-blue-500/50",
glowColor: "rgba(59, 130, 246, 0.3)",
},
@ -73,7 +73,7 @@ const ARMS: Arm[] = [
textColor: "text-red-400",
href: "https://aethex.foundation",
icon: "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2Fc02cb1bf5056479bbb3ea4bd91f0d472?format=webp&width=800",
tip: "Community & education initiatives",
tip: "Community & education",
shadowColor: "shadow-red-500/50",
glowColor: "rgba(239, 68, 68, 0.3)",
external: true,
@ -86,7 +86,7 @@ const ARMS: Arm[] = [
textColor: "text-purple-400",
href: "/nexus",
icon: "https://cdn.builder.io/api/v1/image/assets%2Ffc53d607e21d497595ac97e0637001a1%2F6df123b87a144b1fb99894d94198d97b?format=webp&width=800",
tip: "Talent marketplace & collaboration",
tip: "Talent marketplace",
shadowColor: "shadow-purple-500/50",
glowColor: "rgba(168, 85, 247, 0.3)",
},

View file

@ -22,25 +22,25 @@ export default function Careers() {
icon: <Microscope className="h-6 w-6" />,
title: "Innovation First",
description:
"We push boundaries and explore cutting-edge technologies daily",
"Push boundaries and explore cutting-edge technologies",
},
{
icon: <Heart className="h-6 w-6" />,
title: "People Matter",
description:
"We invest in our team's growth, health, and work-life balance",
"Invest in team growth, health, and work-life balance",
},
{
icon: <Zap className="h-6 w-6" />,
title: "Ship It",
description:
"We believe in execution over perfection—iterate and learn fast",
"Execute over perfection—iterate and learn fast",
},
{
icon: <Users className="h-6 w-6" />,
title: "Collaboration",
description:
"Great ideas come from diverse teams working together openly",
"Great ideas come from diverse teams working openly",
},
];
@ -49,8 +49,8 @@ export default function Careers() {
"Comprehensive health insurance (medical, dental, vision)",
"Unlimited PTO",
"Remote-first, work from anywhere",
"Equipment budget for your home office",
"Professional development fund ($5k/year)",
"Equipment budget",
"Professional development ($5k/year)",
"Team offsites & retreats",
"Stock options",
"Parental leave",
@ -67,7 +67,7 @@ export default function Careers() {
level: "Senior",
type: "Full-time",
description:
"Lead architecture and implementation of next-generation platform systems",
"Lead platform architecture and implementation",
},
{
title: "Game Developer",
@ -75,7 +75,7 @@ export default function Careers() {
location: "Remote",
level: "Mid-level",
type: "Full-time",
description: "Ship games monthly with our world-class production team",
description: "Ship games monthly with world-class team",
},
{
title: "Research Scientist",
@ -84,7 +84,7 @@ export default function Careers() {
level: "Senior",
type: "Full-time",
description:
"Explore AI/ML applications in game development and interactive experiences",
"Explore AI/ML in game development and interactive experiences",
},
{
title: "Product Manager",
@ -93,7 +93,7 @@ export default function Careers() {
level: "Mid-level",
type: "Full-time",
description:
"Shape the future of our developer tools and platforms",
"Shape the future of developer tools and platforms",
},
{
title: "UX/UI Designer",
@ -102,7 +102,7 @@ export default function Careers() {
level: "Mid-level",
type: "Full-time",
description:
"Design beautiful, intuitive interfaces for millions of developers",
"Design beautiful interfaces for developers",
},
{
title: "DevOps Engineer",
@ -110,7 +110,7 @@ export default function Careers() {
location: "Remote",
level: "Senior",
type: "Full-time",
description: "Build the infrastructure that powers AeThex at scale",
description: "Build infrastructure that powers AeThex at scale",
},
];

View file

@ -66,12 +66,11 @@ export default function Contact() {
<div className="container mx-auto px-4 max-w-5xl space-y-10">
<div className="grid md:grid-cols-2 gap-8 items-start">
<div className="space-y-3">
<h1 className="text-4xl font-bold text-gradient-purple">
<h1 className="text-3xl font-bold text-gradient-purple">
Contact Us
</h1>
<p className="text-muted-foreground">
Have a project or question? We typically respond within 12
business days.
We respond within 12 business days
</p>
<Card className="bg-card/50 border-border/50">
<CardContent className="p-6 space-y-3">

View file

@ -78,8 +78,8 @@ export default function Corp() {
const services = [
{
title: "Custom Software Development",
description: "Bespoke applications built for enterprise scale",
title: "Custom Software",
description: "Enterprise applications",
icon: Code,
examples: [
"Web & mobile applications",
@ -90,8 +90,8 @@ export default function Corp() {
color: "from-blue-500 to-cyan-500",
},
{
title: "Technology Consulting",
description: "Strategic guidance for digital transformation",
title: "Tech Consulting",
description: "Digital transformation",
icon: Briefcase,
examples: [
"Architecture design",
@ -102,8 +102,8 @@ export default function Corp() {
color: "from-purple-500 to-pink-500",
},
{
title: "Game Development Services",
description: "Specialized expertise for gaming companies",
title: "Game Development",
description: "Metaverse & gaming",
icon: Rocket,
examples: [
"Full game production",

View file

@ -304,14 +304,14 @@ export default function Dashboard() {
</div>
<Button
onClick={() => navigate("/login")}
className="w-full bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-700 hover:to-blue-700 text-white text-lg py-6"
className="w-full bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-700 hover:to-blue-700 text-white py-6"
>
Sign In to Dashboard
</Button>
<Button
onClick={() => navigate("/onboarding")}
variant="outline"
className="w-full text-lg py-6 border-purple-500/30 text-purple-300 hover:bg-purple-500/10"
className="w-full py-6 border-purple-500/30 text-purple-300 hover:bg-purple-500/10"
>
Create New Account
</Button>
@ -326,15 +326,15 @@ export default function Dashboard() {
return (
<Layout>
<div className="min-h-screen bg-gradient-to-b from-black via-purple-950/20 to-black">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-6xl space-y-8">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-6xl space-y-12">
{/* Header Section */}
<div className="space-y-4 animate-slide-down">
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div className="space-y-2">
<h1 className="text-5xl md:text-6xl font-bold bg-gradient-to-r from-purple-300 via-blue-300 to-purple-300 bg-clip-text text-transparent">
<h1 className="text-4xl md:text-5xl font-bold bg-gradient-to-r from-purple-300 via-blue-300 to-purple-300 bg-clip-text text-transparent">
Dashboard
</h1>
<p className="text-gray-400 text-lg">
<p className="text-gray-400">
Welcome back,{" "}
<span className="text-purple-300 font-semibold">
{profile?.full_name || user.email?.split("@")[0]}
@ -413,15 +413,15 @@ export default function Dashboard() {
<TabsContent value="realms" className="space-y-6 animate-fade-in">
{/* Developer CTA Card */}
{user && (
<Card className="p-6 bg-gradient-to-br from-primary/10 to-primary/5 border-primary/20 hover:border-primary/40 transition-all">
<div className="flex flex-col md:flex-row items-start gap-4">
<div className="p-3 bg-primary/20 rounded-lg shrink-0">
<Card className="p-8 bg-gradient-to-br from-primary/10 to-primary/5 border-primary/20 hover:border-primary/40 transition-all">
<div className="flex flex-col md:flex-row items-start gap-6">
<div className="p-4 bg-primary/20 rounded-lg shrink-0">
<Code className="w-6 h-6 text-primary" />
</div>
<div className="flex-1">
<h3 className="text-lg font-semibold mb-2">Building with AeThex?</h3>
<p className="text-sm text-muted-foreground mb-4">
Get API keys, access comprehensive documentation, and explore developer tools to integrate AeThex into your applications.
<h3 className="text-xl font-semibold mb-3">Building with AeThex?</h3>
<p className="text-base text-muted-foreground mb-6">
Get API keys and access developer tools
</p>
<div className="flex flex-wrap gap-3">
<Link to="/dev-platform/dashboard">
@ -432,12 +432,7 @@ export default function Dashboard() {
</Link>
<Link to="/dev-platform/api-reference">
<Button size="sm" variant="outline">
View API Docs
</Button>
</Link>
<Link to="/dev-platform/templates">
<Button size="sm" variant="outline">
Browse Templates
View Docs
</Button>
</Link>
</div>
@ -446,7 +441,7 @@ export default function Dashboard() {
</Card>
)}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{ARMS.map((arm) => {
const IconComponent = arm.icon;
return (
@ -465,7 +460,7 @@ export default function Dashboard() {
<Card
className={`bg-gradient-to-br ${arm.bgGradient} border transition-all duration-300 h-full hover:shadow-lg hover:shadow-purple-500/20 ${arm.borderColor} cursor-pointer`}
>
<CardContent className="p-6 space-y-4">
<CardContent className="p-8 space-y-6">
<div className="flex items-start justify-between">
<div className="space-y-1">
<div className="flex items-center gap-3">

View file

@ -84,12 +84,11 @@ export default function Downloads() {
<Badge variant="outline" className="mb-4 border-purple-500/50 text-purple-400">
Version {CURRENT_VERSION}
</Badge>
<h1 className="text-4xl md:text-5xl font-bold mb-4 bg-gradient-to-r from-white via-purple-400 to-blue-400 bg-clip-text text-transparent">
<h1 className="text-3xl md:text-4xl font-bold mb-4 bg-gradient-to-r from-white via-purple-400 to-blue-400 bg-clip-text text-transparent">
Download AeThex Desktop
</h1>
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
The AeThex Desktop Terminal brings the full power of the platform to your computer.
Access realms, manage projects, and stay connected with your community.
Desktop Terminal brings full platform access to your computer. Manage projects and stay connected.
</p>
</div>

View file

@ -26,7 +26,7 @@ import {
TrendingUp,
Heart,
MessageSquare,
Avatar,
User,
} from "lucide-react";
import { useEffect, useMemo, useState } from "react";
import {

View file

@ -17,6 +17,7 @@ import {
Compass,
ExternalLink,
} from "lucide-react";
import { useNavigate } from "react-router-dom";
import { useEffect, useState, useRef } from "react";
import LoadingScreen from "@/components/LoadingScreen";
@ -95,7 +96,7 @@ export default function Foundation() {
</div>
</div>
<div className="container mx-auto px-4 max-w-6xl space-y-20 py-16 lg:py-24">
<div className="container mx-auto px-4 max-w-6xl space-y-24 py-16 lg:py-24">
{/* Hero Section */}
<div className="text-center space-y-8 animate-slide-down">
<div className="flex justify-center mb-6">
@ -112,12 +113,12 @@ export default function Foundation() {
501(c)(3) Non-Profit Organization
</Badge>
<h1 className="text-5xl md:text-6xl lg:text-7xl font-black bg-gradient-to-r from-red-300 via-pink-300 to-red-300 bg-clip-text text-transparent">
<h1 className="text-5xl md:text-6xl lg:text-7xl font-bold bg-gradient-to-r from-red-300 via-pink-300 to-red-300 bg-clip-text text-transparent">
AeThex Foundation
</h1>
<p className="text-xl md:text-2xl text-gray-300 max-w-3xl mx-auto leading-relaxed">
Building community, empowering developers, and advancing game development through open-source innovation and mentorship.
<p className="text-lg md:text-xl text-gray-300 max-w-3xl mx-auto leading-relaxed">
501(c)(3) non-profit advancing game development
</p>
{/* TL;DR Section */}

View file

@ -154,12 +154,12 @@ export default function GameForge() {
Foundation's Game Production Studio
</Badge>
<h1 className={`text-5xl md:text-6xl lg:text-7xl font-black text-green-300 leading-tight ${theme.fontClass}`}>
<h1 className={`text-5xl md:text-6xl lg:text-7xl font-bold text-green-300 leading-tight ${theme.fontClass}`}>
Ship Games Every Month
</h1>
<p className="text-xl md:text-2xl text-green-100/80 max-w-3xl mx-auto leading-relaxed">
AeThex GameForge is a master-apprentice mentorship program where teams of 5 developers ship real games in 30-day sprints.
<p className="text-lg md:text-xl text-green-100/80 max-w-3xl mx-auto leading-relaxed">
Ship real games in 30-day sprints
</p>
{/* TL;DR Section */}

View file

@ -132,20 +132,20 @@ export default function GetStarted() {
const platformFeatures = [
{
title: "XP & Leveling System",
description: "Earn XP for daily logins, completing your profile, creating posts, and earning badges. Level up to unlock new features and recognition.",
title: "XP & Leveling",
description: "Earn XP and level up to unlock features",
icon: Trophy,
color: "from-yellow-500 to-amber-600",
},
{
title: "AI Intelligent Agents",
description: "Access 10 specialized AI personas for guidance on networking, game development, ethics, architecture, and more.",
title: "AI Agents",
description: "10 specialized AI personas for guidance",
icon: Bot,
color: "from-purple-500 to-violet-600",
},
{
title: "Creator Passports",
description: "Build a portable profile that aggregates your achievements, verified skills, project history, and mentorship contributions.",
description: "Portable profile with achievements and skills",
icon: IdCard,
color: "from-cyan-500 to-blue-600",
},

View file

@ -1,4 +1,4 @@
import { useState, useEffect } from "react";
import { useState } from "react";
import SEO from "@/components/SEO";
import Layout from "@/components/Layout";
import { Button } from "@/components/ui/button";
@ -27,7 +27,7 @@ const ecosystemPillars = [
{
icon: Boxes,
title: "Six Realms",
description: "Nexus, GameForge, Foundation, Labs, Corp, and Staff—each with unique APIs and capabilities",
description: "Specialized APIs for every use case",
href: "/realms",
gradient: "from-purple-500 via-purple-600 to-indigo-600",
accentColor: "hsl(var(--primary))",
@ -35,7 +35,7 @@ const ecosystemPillars = [
{
icon: Database,
title: "Developer APIs",
description: "Comprehensive REST APIs for users, content, achievements, and more",
description: "REST APIs for all platforms",
href: "/dev-platform/api-reference",
gradient: "from-blue-500 via-blue-600 to-cyan-600",
accentColor: "hsl(var(--primary))",
@ -43,7 +43,7 @@ const ecosystemPillars = [
{
icon: Terminal,
title: "SDK & Tools",
description: "TypeScript SDK, CLI tools, and pre-built templates to ship faster",
description: "Ship faster with TypeScript SDK",
href: "/dev-platform/quick-start",
gradient: "from-cyan-500 via-teal-600 to-emerald-600",
accentColor: "hsl(var(--primary))",
@ -51,7 +51,7 @@ const ecosystemPillars = [
{
icon: Layers,
title: "Marketplace",
description: "Premium integrations, plugins, and components from the community",
description: "Premium plugins & integrations",
href: "/dev-platform/marketplace",
gradient: "from-emerald-500 via-green-600 to-lime-600",
accentColor: "hsl(var(--primary))",
@ -59,7 +59,7 @@ const ecosystemPillars = [
{
icon: Users,
title: "Community",
description: "Join 12,000+ developers building on AeThex",
description: "12K+ developers building together",
href: "/community",
gradient: "from-amber-500 via-orange-600 to-red-600",
accentColor: "hsl(var(--primary))",
@ -67,7 +67,7 @@ const ecosystemPillars = [
{
icon: Trophy,
title: "Opportunities",
description: "Get paid to build—contracts, bounties, and commissions",
description: "Get paid to build",
href: "/opportunities",
gradient: "from-pink-500 via-rose-600 to-red-600",
accentColor: "hsl(var(--primary))",
@ -84,48 +84,39 @@ const stats = [
const features = [
{
icon: Layers,
title: "Cross-Platform Integration Layer",
description: "One unified API to build across Roblox, VRChat, RecRoom, Spatial, Decentraland, The Sandbox, Minecraft, Meta Horizon, Fortnite, and Zepeto—no more managing separate platform SDKs or gated gardens",
title: "Cross-Platform Integration",
description: "One API for all metaverse platforms",
},
{
icon: Code2,
title: "Enterprise-Grade Developer Tools",
description: "TypeScript SDK, REST APIs, unified authentication, cross-platform achievements, content delivery, and CLI tools—all integrated and production-ready",
title: "Enterprise Developer Tools",
description: "Production-ready SDK and APIs",
},
{
icon: Gamepad2,
title: "Six Specialized Realms",
description: "Nexus (social hub), GameForge (games), Foundation (education), Labs (AI/innovation), Corp (business), Staff (governance)—each with unique APIs and tools",
description: "Unique APIs for every use case",
},
{
icon: Trophy,
title: "Monetize Your Skills",
description: "Get paid to build—access contracts, bounties, and commissions. 12K+ developers earning while creating cross-platform games, apps, and integrations",
description: "12K+ developers earning on AeThex",
},
{
icon: Users,
title: "Thriving Creator Economy",
description: "Join squads, collaborate on projects, share assets in the marketplace that work across all platforms, and grow your reputation across all six realms",
title: "Creator Economy",
description: "Collaborate and grow your reputation",
},
{
icon: Rocket,
title: "Ship Everywhere, Fast",
description: "150+ cross-platform code examples, pre-built templates for VRChat, RecRoom, Spatial, Decentraland, The Sandbox, Roblox, and more—OAuth integration, Supabase backend, and one-command deployment to every metaverse",
title: "Ship Fast",
description: "150+ examples and one-click deployment",
},
];
export default function Index() {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const [hoveredCard, setHoveredCard] = useState<number | null>(null);
useEffect(() => {
const handleMouseMove = (e: MouseEvent) => {
setMousePosition({ x: e.clientX, y: e.clientY });
};
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
}, []);
return (
<Layout hideFooter>
<SEO
@ -141,10 +132,10 @@ export default function Index() {
{/* Animated Background */}
<div className="fixed inset-0 pointer-events-none overflow-hidden">
<motion.div
className="absolute w-[800px] h-[800px] rounded-full blur-[128px] opacity-20 bg-primary/30"
className="absolute w-[600px] h-[600px] rounded-full blur-[100px] opacity-15 bg-primary/30"
style={{
left: mousePosition.x - 400,
top: mousePosition.y - 400,
left: '10%',
top: '20%',
}}
animate={{
x: [0, 50, 0],
@ -216,7 +207,7 @@ export default function Index() {
<div className="absolute bottom-0 right-0 w-64 h-64 border-b-2 border-r-2 border-primary/30" />
</div>
<div className="relative space-y-32 pb-32">
<div className="relative space-y-40 pb-40">
<section className="relative min-h-[90vh] flex items-center justify-center overflow-hidden pt-20">
<div className="relative text-center max-w-6xl mx-auto space-y-10 px-4">
<motion.div
@ -237,7 +228,7 @@ export default function Index() {
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.8, delay: 0.2 }}
>
<h1 className="text-7xl md:text-8xl lg:text-9xl font-black tracking-tight leading-none">
<h1 className="text-5xl md:text-6xl lg:text-7xl font-black tracking-tight leading-none">
Build on
<br />
<span className="relative inline-block mt-4">
@ -264,7 +255,7 @@ export default function Index() {
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.4 }}
className="text-2xl md:text-3xl text-muted-foreground max-w-4xl mx-auto leading-relaxed font-light"
className="text-xl md:text-2xl text-muted-foreground max-w-4xl mx-auto leading-relaxed font-light"
>
The <span className="text-primary font-bold">integration layer</span> connecting all metaverse platforms.
<br className="hidden md:block" />
@ -313,19 +304,19 @@ export default function Index() {
<Link to="/dev-platform/quick-start">
<Button
size="lg"
className="text-xl px-10 h-16 bg-primary hover:bg-primary/90 shadow-[0_0_40px_rgba(168,85,247,0.6)] hover:shadow-[0_0_60px_rgba(168,85,247,0.8)] hover:scale-105 transition-all duration-300 font-black uppercase tracking-wide border-2 border-primary/50"
className="text-base px-8 h-12 bg-primary hover:bg-primary/90 shadow-[0_0_40px_rgba(168,85,247,0.6)] hover:shadow-[0_0_60px_rgba(168,85,247,0.8)] hover:scale-105 transition-all duration-300 font-bold uppercase tracking-wide border-2 border-primary/50"
>
Start Building
<Rocket className="w-6 h-6 ml-3" />
<Rocket className="w-5 h-5 ml-2" />
</Button>
</Link>
<Link to="/dev-platform/api-reference">
<Button
size="lg"
variant="outline"
className="text-xl px-10 h-16 backdrop-blur-xl bg-background/50 border-2 border-primary/40 hover:bg-primary/10 hover:border-primary/60 shadow-[0_0_20px_rgba(168,85,247,0.3)] hover:shadow-[0_0_40px_rgba(168,85,247,0.5)] hover:scale-105 transition-all duration-300 font-black uppercase tracking-wide"
className="text-base px-8 h-12 backdrop-blur-xl bg-background/50 border-2 border-primary/40 hover:bg-primary/10 hover:border-primary/60 shadow-[0_0_20px_rgba(168,85,247,0.3)] hover:shadow-[0_0_40px_rgba(168,85,247,0.5)] hover:scale-105 transition-all duration-300 font-bold uppercase tracking-wide"
>
<BookOpen className="w-6 h-6 mr-3" />
<BookOpen className="w-5 h-5 mr-2" />
Explore APIs
</Button>
</Link>
@ -376,19 +367,19 @@ export default function Index() {
</motion.div>
</section>
<section className="space-y-12 px-4">
<section className="space-y-20 px-4">
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="text-center space-y-4"
className="text-center space-y-6"
>
<h2 className="text-5xl md:text-6xl font-black text-primary">
The AeThex Ecosystem
</h2>
<p className="text-xl text-muted-foreground max-w-3xl mx-auto">
Six interconnected realms, each with unique capabilities and APIs to power your applications
Six interconnected realms with unique APIs
</p>
</motion.div>
@ -449,23 +440,23 @@ export default function Index() {
</div>
</section>
<section className="space-y-12 px-4">
<section className="space-y-20 px-4">
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="text-center space-y-4"
className="text-center space-y-6"
>
<h2 className="text-5xl md:text-6xl font-black text-primary">
Why Build on AeThex?
</h2>
<p className="text-xl text-muted-foreground max-w-3xl mx-auto">
Join a growing ecosystem designed for creators, developers, and entrepreneurs
Built for creators and developers
</p>
</motion.div>
<div className="grid md:grid-cols-3 gap-8 max-w-6xl mx-auto">
<div className="grid md:grid-cols-3 gap-10 max-w-6xl mx-auto">
{features.map((feature, index) => (
<motion.div
key={feature.title}
@ -474,13 +465,13 @@ export default function Index() {
viewport={{ once: true }}
transition={{ duration: 0.6, delay: index * 0.2 }}
>
<Card className="p-8 space-y-6 backdrop-blur-xl bg-background/50 border-primary/20 hover:border-primary/40 hover:scale-105 transition-all duration-300 h-full">
<Card className="p-10 space-y-8 backdrop-blur-xl bg-background/50 border-primary/20 hover:border-primary/40 hover:scale-105 transition-all duration-300 h-full">
<div className="w-16 h-16 rounded-2xl bg-primary flex items-center justify-center shadow-2xl shadow-primary/50">
<feature.icon className="w-8 h-8 text-primary-foreground" />
</div>
<div className="space-y-3">
<div className="space-y-4">
<h3 className="text-2xl font-bold">{feature.title}</h3>
<p className="text-muted-foreground leading-relaxed">
<p className="text-lg text-muted-foreground">
{feature.description}
</p>
</div>
@ -572,20 +563,20 @@ export default function Index() {
<Link to="/dev-platform/dashboard">
<Button
size="lg"
className="text-xl px-10 h-16 bg-primary hover:bg-primary/90 shadow-[0_0_40px_rgba(168,85,247,0.6)] hover:shadow-[0_0_60px_rgba(168,85,247,0.8)] hover:scale-105 transition-all duration-300 font-black uppercase tracking-wide border-2 border-primary/50"
className="text-base px-8 h-12 bg-primary hover:bg-primary/90 shadow-[0_0_40px_rgba(168,85,247,0.6)] hover:shadow-[0_0_60px_rgba(168,85,247,0.8)] hover:scale-105 transition-all duration-300 font-bold uppercase tracking-wide border-2 border-primary/50"
>
Get Your API Key
<ArrowRight className="w-6 h-6 ml-3" />
<ArrowRight className="w-5 h-5 ml-2" />
</Button>
</Link>
<Link to="/realms">
<Button
size="lg"
variant="outline"
className="text-xl px-10 h-16 backdrop-blur-xl bg-background/50 border-2 border-primary/40 hover:bg-primary/10 hover:border-primary/60 shadow-[0_0_20px_rgba(168,85,247,0.3)] hover:shadow-[0_0_40px_rgba(168,85,247,0.5)] hover:scale-105 transition-all duration-300 font-black uppercase tracking-wide"
className="text-base px-8 h-12 backdrop-blur-xl bg-background/50 border-2 border-primary/40 hover:bg-primary/10 hover:border-primary/60 shadow-[0_0_20px_rgba(168,85,247,0.3)] hover:shadow-[0_0_40px_rgba(168,85,247,0.5)] hover:scale-105 transition-all duration-300 font-bold uppercase tracking-wide"
>
Explore Realms
<Boxes className="w-6 h-6 ml-3" />
<Boxes className="w-5 h-5 ml-2" />
</Button>
</Link>
</motion.div>

View file

@ -0,0 +1,418 @@
import { useState } from "react";
import SEO from "@/components/SEO";
import Layout from "@/components/Layout";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Link } from "react-router-dom";
import {
ArrowRight,
Terminal,
Copy,
Check,
BookOpen,
Zap,
Shield,
Globe,
Code2,
Database,
Users,
Boxes,
Layers,
Trophy,
Gamepad2,
} from "lucide-react";
const codeExample = `import { AeThex } from '@aethex/sdk';
const client = new AeThex({ apiKey: process.env.AETHEX_KEY });
// Authenticate user across platforms
const user = await client.passport.authenticate({
platform: 'roblox',
userId: '123456789'
});
// Sync achievements, inventory, progress
await client.sync({
achievements: user.achievements,
inventory: user.inventory,
progress: user.gameProgress
});`;
const ecosystemPillars = [
{
icon: Boxes,
title: "Six Realms",
description: "Specialized APIs for every use case",
href: "/realms",
gradient: "from-purple-500 to-indigo-600",
},
{
icon: Database,
title: "Developer APIs",
description: "REST APIs for all platforms",
href: "/dev-platform/api-reference",
gradient: "from-blue-500 to-cyan-600",
},
{
icon: Terminal,
title: "SDK & Tools",
description: "Ship faster with TypeScript SDK",
href: "/dev-platform/quick-start",
gradient: "from-cyan-500 to-emerald-600",
},
{
icon: Layers,
title: "Marketplace",
description: "Premium plugins & integrations",
href: "/dev-platform/marketplace",
gradient: "from-emerald-500 to-lime-600",
},
{
icon: Users,
title: "Community",
description: "12K+ developers building together",
href: "/community",
gradient: "from-amber-500 to-red-600",
},
{
icon: Trophy,
title: "Opportunities",
description: "Get paid to build",
href: "/opportunities",
gradient: "from-pink-500 to-red-600",
},
];
const stats = [
{ value: "12K+", label: "Developers" },
{ value: "2.5M+", label: "API Calls/Day" },
{ value: "150+", label: "Examples" },
{ value: "6", label: "Realms" },
];
const features = [
{
icon: Globe,
title: "Cross-Platform Identity",
description: "One passport across Roblox, Minecraft, Fortnite, and more.",
},
{
icon: Database,
title: "Universal Data Sync",
description: "Sync achievements, inventory, and progress with a single API.",
},
{
icon: Shield,
title: "Enterprise Auth",
description: "OAuth 2.0, PKCE, JWT. Production-ready out of the box.",
},
{
icon: Gamepad2,
title: "Game Integration",
description: "Drop-in SDKs for Roblox, Unity, Unreal, and more.",
},
];
const platforms = ["Roblox", "Minecraft", "Fortnite", "Meta Horizon", "Zepeto", "Unity", "Unreal"];
export default function Index() {
const [copied, setCopied] = useState(false);
const copyCode = () => {
navigator.clipboard.writeText(codeExample);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<Layout hideFooter>
<SEO
pageTitle="AeThex | Developer Platform"
description="Build cross-platform experiences with the AeThex SDK. One API for identity, data sync, and authentication across metaverse platforms."
canonical={typeof window !== "undefined" ? window.location.href : undefined}
/>
{/* Subtle background */}
<div className="fixed inset-0 pointer-events-none overflow-hidden -z-10">
<div className="absolute top-0 right-0 w-[600px] h-[600px] rounded-full bg-primary/5 blur-3xl" />
<div className="absolute bottom-0 left-0 w-[500px] h-[500px] rounded-full bg-primary/5 blur-3xl" />
<div
className="absolute inset-0 opacity-[0.02]"
style={{
backgroundImage: `linear-gradient(to right, hsl(var(--primary)) 1px, transparent 1px),
linear-gradient(to bottom, hsl(var(--primary)) 1px, transparent 1px)`,
backgroundSize: "60px 60px",
}}
/>
</div>
<div className="relative min-h-screen">
{/* Hero */}
<section className="relative pt-20 pb-16 px-4">
<div className="max-w-6xl mx-auto">
<div className="grid lg:grid-cols-2 gap-12 items-center">
{/* Left: Value Prop */}
<div className="space-y-6">
<Badge variant="outline" className="text-xs font-mono border-primary/30">
v2.4.0 — TypeScript SDK
</Badge>
<h1 className="text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight">
One API for
<br />
<span className="text-primary">cross-platform games</span>
</h1>
<p className="text-lg text-muted-foreground max-w-lg">
Connect players across Roblox, Minecraft, Fortnite, and more.
Sync identity, achievements, and inventory with a single SDK.
</p>
<div className="flex flex-wrap gap-3 pt-2">
<Link to="/dev-platform/quick-start">
<Button size="lg" className="font-medium shadow-lg shadow-primary/25">
Get Started
<ArrowRight className="w-4 h-4 ml-2" />
</Button>
</Link>
<Link to="/dev-platform/api-reference">
<Button size="lg" variant="outline" className="font-medium">
<BookOpen className="w-4 h-4 mr-2" />
Read Docs
</Button>
</Link>
</div>
{/* Install command */}
<div className="flex items-center gap-2 pt-4">
<code className="flex-1 bg-muted px-4 py-2.5 rounded-lg font-mono text-sm border">
npm install @aethex/sdk
</code>
<Button
size="sm"
variant="ghost"
onClick={() => navigator.clipboard.writeText("npm install @aethex/sdk")}
>
<Copy className="w-4 h-4" />
</Button>
</div>
{/* Stats row */}
<div className="grid grid-cols-4 gap-4 pt-6">
{stats.map((stat) => (
<div key={stat.label} className="text-center">
<p className="text-2xl md:text-3xl font-bold text-primary">{stat.value}</p>
<p className="text-xs text-muted-foreground">{stat.label}</p>
</div>
))}
</div>
</div>
{/* Right: Code Example */}
<div className="relative">
<Card className="bg-zinc-950 border-zinc-800 overflow-hidden shadow-2xl">
<div className="flex items-center justify-between px-4 py-2 border-b border-zinc-800">
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-500/80" />
<div className="w-3 h-3 rounded-full bg-green-500/80" />
</div>
<span className="text-xs text-zinc-500 font-mono">app.ts</span>
<Button
size="sm"
variant="ghost"
className="h-6 text-zinc-400 hover:text-white"
onClick={copyCode}
>
{copied ? <Check className="w-3 h-3" /> : <Copy className="w-3 h-3" />}
</Button>
</div>
<pre className="p-4 text-sm overflow-x-auto">
<code className="text-zinc-300 font-mono whitespace-pre-wrap">
<span className="text-purple-400">import</span>
<span className="text-zinc-300"> {"{"} </span>
<span className="text-yellow-300">AeThex</span>
<span className="text-zinc-300"> {"}"} </span>
<span className="text-purple-400">from</span>
<span className="text-green-400"> '@aethex/sdk'</span>
<span className="text-zinc-300">;</span>
{"\n\n"}
<span className="text-purple-400">const</span>
<span className="text-blue-300"> client</span>
<span className="text-zinc-300"> = </span>
<span className="text-purple-400">new</span>
<span className="text-yellow-300"> AeThex</span>
<span className="text-zinc-300">{"({ "}</span>
<span className="text-blue-300">apiKey</span>
<span className="text-zinc-300">: </span>
<span className="text-blue-300">process.env.</span>
<span className="text-zinc-300">AETHEX_KEY {"});"}</span>
{"\n\n"}
<span className="text-zinc-600">// Authenticate user across platforms</span>
{"\n"}
<span className="text-purple-400">const</span>
<span className="text-blue-300"> user</span>
<span className="text-zinc-300"> = </span>
<span className="text-purple-400">await</span>
<span className="text-blue-300"> client</span>
<span className="text-zinc-300">.passport.</span>
<span className="text-yellow-300">authenticate</span>
<span className="text-zinc-300">{"({"}</span>
{"\n"}
<span className="text-zinc-300">{" "}</span>
<span className="text-blue-300">platform</span>
<span className="text-zinc-300">: </span>
<span className="text-green-400">'roblox'</span>
<span className="text-zinc-300">,</span>
{"\n"}
<span className="text-zinc-300">{" "}</span>
<span className="text-blue-300">userId</span>
<span className="text-zinc-300">: </span>
<span className="text-green-400">'123456789'</span>
{"\n"}
<span className="text-zinc-300">{"});"}</span>
{"\n\n"}
<span className="text-zinc-600">// Sync achievements, inventory, progress</span>
{"\n"}
<span className="text-purple-400">await</span>
<span className="text-blue-300"> client</span>
<span className="text-zinc-300">.</span>
<span className="text-yellow-300">sync</span>
<span className="text-zinc-300">{"({"}</span>
{"\n"}
<span className="text-zinc-300">{" "}</span>
<span className="text-blue-300">achievements</span>
<span className="text-zinc-300">: </span>
<span className="text-blue-300">user</span>
<span className="text-zinc-300">.achievements,</span>
{"\n"}
<span className="text-zinc-300">{" "}</span>
<span className="text-blue-300">inventory</span>
<span className="text-zinc-300">: </span>
<span className="text-blue-300">user</span>
<span className="text-zinc-300">.inventory,</span>
{"\n"}
<span className="text-zinc-300">{" "}</span>
<span className="text-blue-300">progress</span>
<span className="text-zinc-300">: </span>
<span className="text-blue-300">user</span>
<span className="text-zinc-300">.gameProgress</span>
{"\n"}
<span className="text-zinc-300">{"});"}</span>
</code>
</pre>
</Card>
</div>
</div>
</div>
</section>
{/* Platforms */}
<section className="py-6 px-4 border-y border-border/30">
<div className="max-w-6xl mx-auto">
<div className="flex flex-wrap items-center justify-center gap-6 md:gap-10 text-muted-foreground">
<span className="text-sm font-medium">Works with:</span>
{platforms.map((platform) => (
<span key={platform} className="text-sm font-medium hover:text-foreground transition-colors cursor-default">
{platform}
</span>
))}
</div>
</div>
</section>
{/* Ecosystem Pillars */}
<section className="py-20 px-4">
<div className="max-w-6xl mx-auto space-y-12">
<div className="text-center space-y-4">
<h2 className="text-3xl md:text-4xl font-bold">The AeThex Ecosystem</h2>
<p className="text-muted-foreground max-w-2xl mx-auto">
Six interconnected realms with specialized APIs for every use case
</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-5">
{ecosystemPillars.map((pillar) => (
<Link key={pillar.title} to={pillar.href}>
<Card className="group p-6 h-full hover:border-primary/40 transition-all duration-200 hover:shadow-lg hover:shadow-primary/5">
<div className="space-y-4">
<div className={`w-14 h-14 rounded-xl bg-gradient-to-br ${pillar.gradient} flex items-center justify-center shadow-lg group-hover:scale-105 transition-transform`}>
<pillar.icon className="w-7 h-7 text-white" />
</div>
<div className="space-y-2">
<h3 className="text-xl font-semibold group-hover:text-primary transition-colors">
{pillar.title}
</h3>
<p className="text-muted-foreground text-sm">
{pillar.description}
</p>
</div>
<div className="flex items-center text-primary text-sm font-medium group-hover:translate-x-1 transition-transform">
Explore <ArrowRight className="w-4 h-4 ml-1" />
</div>
</div>
</Card>
</Link>
))}
</div>
</div>
</section>
{/* Features */}
<section className="py-20 px-4 bg-muted/30">
<div className="max-w-6xl mx-auto space-y-12">
<div className="text-center space-y-4">
<h2 className="text-3xl md:text-4xl font-bold">Built for game developers</h2>
<p className="text-muted-foreground max-w-2xl mx-auto">
Everything you need to connect players across platforms
</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-5">
{features.map((feature) => (
<Card key={feature.title} className="p-5 space-y-3">
<div className="w-11 h-11 rounded-lg bg-primary/10 flex items-center justify-center">
<feature.icon className="w-5 h-5 text-primary" />
</div>
<h3 className="font-semibold">{feature.title}</h3>
<p className="text-sm text-muted-foreground">{feature.description}</p>
</Card>
))}
</div>
</div>
</section>
{/* CTA */}
<section className="py-20 px-4">
<div className="max-w-4xl mx-auto">
<Card className="p-8 md:p-12 text-center space-y-6 bg-gradient-to-br from-primary/10 via-primary/5 to-background border-primary/20">
<Zap className="w-12 h-12 text-primary mx-auto" />
<h2 className="text-3xl md:text-4xl font-bold">Start building today</h2>
<p className="text-muted-foreground max-w-lg mx-auto">
Get your API key and integrate in minutes. Free tier includes 10K API calls/month.
</p>
<div className="flex flex-wrap gap-4 justify-center pt-2">
<Link to="/dev-platform/dashboard">
<Button size="lg" className="shadow-lg shadow-primary/25">
Get API Key
<ArrowRight className="w-4 h-4 ml-2" />
</Button>
</Link>
<Link to="/dev-platform/quick-start">
<Button size="lg" variant="outline">
View Quick Start
</Button>
</Link>
</div>
</Card>
</div>
</section>
{/* Footer spacer */}
<div className="pb-16" />
</div>
</Layout>
);
}

View file

@ -95,17 +95,17 @@ export default function Investors() {
{
icon: <Layers className="h-5 w-5" />,
title: "Three Engines",
desc: "Studios (services), Platform (community), and Labs (R&D) compound value together.",
desc: "Studios, Platform, and Labs compound value.",
},
{
icon: <Shield className="h-5 w-5" />,
title: "Trust & Quality",
desc: "Security-first engineering and measurable delivery keep churn low and NPS high.",
desc: "Security-first engineering with measurable delivery.",
},
{
icon: <Target className="h-5 w-5" />,
title: "Focused Markets",
desc: "High-signal segments: games, real-time apps, and experience platforms.",
desc: "Games, real-time apps, and experience platforms.",
},
];
@ -134,13 +134,11 @@ export default function Investors() {
<span className="mr-2 inline-flex h-2 w-2 animate-pulse rounded-full bg-red-300" />
Investor Relations
</Badge>
<h1 className="text-4xl font-black tracking-tight text-red-300 sm:text-5xl lg:text-6xl">
<h1 className="text-3xl font-black tracking-tight text-red-300 sm:text-4xl lg:text-5xl">
AeThex | Building With Conviction
</h1>
<p className="text-lg text-red-100/90 sm:text-xl">
We craft reliable, loved software and the platform that powers
creators. Explore our thesis, traction, and how to participate
in compliant offerings.
Reliable software and the platform powering creators. Explore our thesis and participation options.
</p>
<div className="flex flex-col gap-4 sm:flex-row">
<Button

View file

@ -154,9 +154,9 @@ export default function Labs() {
{/* Cyberpunk Background Effects */}
<div className="pointer-events-none absolute inset-0 opacity-[0.12] [background-image:radial-gradient(circle_at_top,#facc15_0,rgba(0,0,0,0.45)_55%,rgba(0,0,0,0.9)_100%)]" />
<div className="pointer-events-none absolute inset-0 bg-[linear-gradient(transparent_0,transparent_calc(100%-1px),rgba(250,204,21,0.05)_calc(100%-1px))] bg-[length:100%_32px]" />
<div className="pointer-events-none absolute inset-0 opacity-[0.08] [background-image:linear-gradient(90deg,rgba(251,191,36,0.1)_1px,transparent_1px),linear-gradient(0deg,rgba(251,191,36,0.1)_1px,transparent_1px)] [background-size:50px_50px] animate-pulse" />
<div className="pointer-events-none absolute top-20 left-10 w-96 h-96 bg-yellow-500/20 rounded-full mix-blend-multiply filter blur-3xl animate-pulse" />
<div className="pointer-events-none absolute bottom-20 right-10 w-96 h-96 bg-yellow-600/10 rounded-full mix-blend-multiply filter blur-3xl animate-pulse" />
<div className="pointer-events-none absolute inset-0 opacity-[0.08] [background-image:linear-gradient(90deg,rgba(251,191,36,0.1)_1px,transparent_1px),linear-gradient(0deg,rgba(251,191,36,0.1)_1px,transparent_1px)] [background-size:50px_50px]" />
<div className="pointer-events-none absolute top-20 left-10 w-96 h-96 bg-yellow-500/20 rounded-full mix-blend-multiply filter blur-3xl" />
<div className="pointer-events-none absolute bottom-20 right-10 w-96 h-96 bg-yellow-600/10 rounded-full mix-blend-multiply filter blur-3xl" />
<main className="relative z-10">
{/* Hero Section */}
@ -177,12 +177,12 @@ export default function Labs() {
Advanced Research & Development
</Badge>
<h1 className={`text-5xl md:text-6xl lg:text-7xl font-black text-yellow-300 leading-tight ${theme.fontClass}`}>
<h1 className={`text-5xl md:text-6xl lg:text-7xl font-bold text-yellow-300 leading-tight ${theme.fontClass}`}>
The Innovation Engine
</h1>
<p className="text-xl md:text-2xl text-yellow-100/80 max-w-3xl mx-auto leading-relaxed">
Breakthrough R&D pushing the boundaries of what's possible in software, AI, games, and digital experiences.
<p className="text-lg md:text-xl text-yellow-100/80 max-w-3xl mx-auto leading-relaxed">
Breakthrough R&D in software, AI, and games
</p>
{/* TL;DR Section */}

View file

@ -123,14 +123,12 @@ export default function Nexus() {
AeThex Nexus
</Badge>
<h1 className="text-4xl font-black tracking-tight text-purple-300 sm:text-5xl lg:text-6xl">
<h1 className="text-4xl font-bold tracking-tight text-purple-300 sm:text-5xl">
The Talent Nexus
</h1>
<p className="text-lg text-purple-100/90 sm:text-xl">
Connect creators with opportunities across all AeThex arms.
Find talent, post jobs, and build amazing teams in a unified
marketplace powered by both AeThex and DevConnect.
<p className="text-base text-purple-100/90">
Connect creators with opportunities across all AeThex arms
</p>
<div className="flex flex-col sm:flex-row gap-4">

View file

@ -71,7 +71,7 @@ export default function Projects() {
Projects & Testimonials
</h1>
<p className="text-muted-foreground max-w-2xl mt-1">
Studio initiatives across AeThex Platform, Labs, and Studio.
AeThex showcase portfolio
</p>
</div>
{isOwner && (

View file

@ -75,7 +75,7 @@ export default function Realms() {
/>
</div>
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-6xl relative">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-6xl relative space-y-20">
{/* Hero Section */}
<motion.div
initial={{ opacity: 0, y: 20 }}
@ -91,10 +91,8 @@ export default function Realms() {
Choose Your{" "}
<span className="text-primary drop-shadow-[0_0_25px_rgba(168,85,247,0.8)]">Realm</span>
</h1>
<p className="text-xl md:text-2xl text-muted-foreground max-w-3xl mx-auto font-light">
Each realm has unique tools, communities, and opportunities.
<br className="hidden md:block" />
Your dashboard adapts to your choice.
<p className="text-lg md:text-xl text-muted-foreground max-w-3xl mx-auto font-light">
Unique tools and communities for every role
</p>
</motion.div>

View file

@ -87,7 +87,7 @@ export default function Squads() {
return (
<Layout>
<div className="min-h-screen bg-[radial-gradient(circle_at_top,_rgba(110,141,255,0.12),transparent_60%)]">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-6xl space-y-8">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-6xl space-y-12">
{/* Header */}
<section className="rounded-3xl border border-border/40 bg-background/80 p-6 shadow-2xl backdrop-blur">
<div className="flex items-start justify-between">
@ -96,8 +96,7 @@ export default function Squads() {
Squads Hub
</h1>
<p className="mt-1 text-sm text-muted-foreground">
Form squads and ship projects together. Match by skill,
timezone, and goals.
Form squads and ship projects together
</p>
</div>
<div className="hidden sm:block p-3 rounded-2xl bg-gradient-to-br from-aethex-500/10 to-neon-blue/10">

View file

@ -102,11 +102,11 @@ export default function Teams() {
return (
<Layout>
<div className="min-h-screen bg-[radial-gradient(circle_at_top,_rgba(110,141,255,0.12),transparent_60%)]">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-6xl space-y-8">
<div className="container mx-auto px-4 sm:px-6 lg:px-8 py-8 lg:py-12 max-w-6xl space-y-12">
<section className="rounded-3xl border border-border/40 bg-background/80 p-6 shadow-2xl backdrop-blur">
<h1 className="text-3xl font-semibold text-foreground">Teams</h1>
<p className="mt-1 text-sm text-muted-foreground">
Create a team and collaborate with members across projects.
Collaborate across projects
</p>
</section>

View file

@ -30,12 +30,11 @@ export default function Trust() {
<Badge variant="outline" className="mx-auto">
Transparency
</Badge>
<h1 className="text-4xl font-bold text-gradient-purple">
<h1 className="text-3xl font-bold text-gradient-purple">
Company & Governance
</h1>
<p className="text-muted-foreground max-w-3xl mx-auto">
Clear, verifiable information about AeThex: leadership, legal
entity, jurisdiction, policies, and status.
Leadership, legal entity, jurisdiction, policies, and status.
</p>
</div>
@ -91,17 +90,13 @@ export default function Trust() {
<CardContent className="text-sm text-muted-foreground space-y-2">
<ul className="list-disc pl-5 space-y-1">
<li>
Phased disclosures cadence: Phase 1 (executive roster +
roles), Phase 2 (board/advisor bios and affiliations), Phase
3 (jurisdictional filings & compliance references).
Phase 1: executive roster & roles | Phase 2: board/advisor profiles | Phase 3: compliance filings.
</li>
<li>
Operational policies and escalation paths are documented in
the Transparency hub.
Policies and escalation paths in Transparency hub.
</li>
<li>
Verified channels: website, docs, and official social
accounts noted below.
Verified channels: website, docs, and social accounts.
</li>
</ul>
<div className="text-xs text-muted-foreground/80">

View file

@ -86,7 +86,7 @@ export default function AdminEthosVerification() {
setRequests(data);
} catch (error) {
console.error(error);
toast.error("Failed to load verification requests");
toast.error({ title: "Failed to load verification requests" });
} finally {
setLoading(false);
}
@ -124,11 +124,11 @@ export default function AdminEthosVerification() {
if (!response.ok) throw new Error(`Failed to ${confirmAction} artist`);
toast.success(
confirmAction === "approve"
toast.success({
title: confirmAction === "approve"
? "Artist verified successfully! Email sent."
: "Artist application rejected. Email sent.",
);
});
setIsConfirming(false);
setSelectedRequest(null);
@ -136,7 +136,7 @@ export default function AdminEthosVerification() {
fetchRequests();
} catch (error) {
console.error(error);
toast.error(`Failed to ${confirmAction} artist`);
toast.error({ title: `Failed to ${confirmAction} artist` });
}
};

View file

@ -0,0 +1,436 @@
import Layout from "@/components/Layout";
import SEO from "@/components/SEO";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Link } from "react-router-dom";
import {
Package,
Shield,
Users,
Zap,
Copy,
CheckCircle2,
ArrowRight,
ExternalLink,
Github,
Terminal,
Code,
Lock,
Globe,
FileText,
} from "lucide-react";
import { useState } from "react";
const PACKAGE_VERSION = "1.0.0";
const features = [
{
icon: Users,
title: "Passport",
description: "Universal identity across platforms - authenticate users seamlessly on Roblox, web, and more",
color: "text-blue-500",
bgColor: "bg-blue-500/10",
},
{
icon: Zap,
title: "DataSync",
description: "Cross-platform data synchronization for real-time state management",
color: "text-yellow-500",
bgColor: "bg-yellow-500/10",
},
{
icon: Shield,
title: "SafeInput",
description: "PII detection and scrubbing - critical for CODEX and child safety compliance",
color: "text-green-500",
bgColor: "bg-green-500/10",
},
{
icon: Lock,
title: "Compliance",
description: "Built-in COPPA/FERPA compliance checks with audit trail logging",
color: "text-purple-500",
bgColor: "bg-purple-500/10",
},
];
const platforms = [
{ name: "Roblox", supported: true },
{ name: "UEFN", supported: true },
{ name: "Unity", supported: true },
{ name: "Web", supported: true },
{ name: "Node.js", supported: true },
];
const codeExamples = {
passport: `const { Passport } = require('@aethex.os/core');
const passport = new Passport('user123', 'PlayerOne');
await passport.verify();
await passport.syncAcross(['roblox', 'web']);`,
safeinput: `const { SafeInput } = require('@aethex.os/core');
// Detect PII
const detected = SafeInput.detectPII('Call me at 555-1234');
// Returns: ['phone']
// Scrub PII
const clean = SafeInput.scrub('My email is user@example.com');
// Returns: 'My email is [EMAIL_REDACTED]'
// Validate input
const result = SafeInput.validate('PlayerName123');
if (result.valid) {
console.log('Safe to use');
}`,
compliance: `const { Compliance } = require('@aethex.os/core');
// Age gate
if (Compliance.isCOPPACompliant(userAge)) {
// User is 13+
}
// Check data collection permission
if (Compliance.canCollectData(user)) {
// Safe to collect
}
// Log compliance check for audit
Compliance.logCheck(userId, 'leaderboard_submission', true);`,
datasync: `const { DataSync } = require('@aethex.os/core');
// Sync data across platforms
await DataSync.sync({
inventory: playerInventory,
progress: gameProgress
}, ['roblox', 'web']);
// Pull data from specific platform
const data = await DataSync.pull(userId, 'roblox');`,
};
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<Button
variant="ghost"
size="sm"
onClick={handleCopy}
className="absolute top-2 right-2 h-8 w-8 p-0"
>
{copied ? (
<CheckCircle2 className="h-4 w-4 text-green-500" />
) : (
<Copy className="h-4 w-4" />
)}
</Button>
);
}
function CodeBlock({ code, language = "javascript" }: { code: string; language?: string }) {
return (
<div className="relative">
<CopyButton text={code} />
<pre className="bg-slate-900 border border-slate-700 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-slate-300 font-mono">{code}</code>
</pre>
</div>
);
}
export default function AethexLang() {
return (
<Layout>
<SEO
pageTitle="@aethex.os/core | AeThex Language Standard Library"
description="Cross-platform utilities for authentication, data sync, and compliance. Build safer metaverse experiences with built-in COPPA support."
/>
<div className="space-y-16">
{/* Hero Section */}
<section className="text-center max-w-4xl mx-auto space-y-6">
<div className="flex items-center justify-center gap-3 mb-4">
<Badge className="text-sm px-4 py-1 bg-purple-500/20 text-purple-400 border-purple-500/30">
v{PACKAGE_VERSION}
</Badge>
<Badge variant="outline" className="text-sm px-4 py-1">
MIT License
</Badge>
</div>
<h1 className="text-5xl font-bold tracking-tight">
<span className="text-primary">@aethex.os/core</span>
</h1>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
AeThex Language Standard Library Cross-platform utilities for authentication,
data sync, and compliance across the metaverse.
</p>
{/* Install Command */}
<div className="relative max-w-md mx-auto">
<div className="flex items-center gap-3 bg-slate-900 border border-slate-700 rounded-lg px-4 py-3">
<Terminal className="h-5 w-5 text-slate-500" />
<code className="text-sm font-mono text-slate-300 flex-1 text-left">
npm install @aethex.os/core
</code>
<CopyButton text="npm install @aethex.os/core" />
</div>
</div>
<div className="flex gap-4 justify-center pt-4">
<a
href="https://www.npmjs.com/package/@aethex.os/core"
target="_blank"
rel="noopener noreferrer"
>
<Button size="lg">
<Package className="w-4 h-4 mr-2" />
View on npm
<ExternalLink className="w-4 h-4 ml-2" />
</Button>
</a>
<a
href="https://github.com/AeThex-Corporation/AeThexOS"
target="_blank"
rel="noopener noreferrer"
>
<Button size="lg" variant="outline">
<Github className="w-4 h-4 mr-2" />
GitHub
</Button>
</a>
</div>
</section>
{/* Platform Support */}
<section className="text-center">
<p className="text-sm text-muted-foreground mb-4">Works everywhere you build</p>
<div className="flex flex-wrap justify-center gap-3">
{platforms.map((platform) => (
<Badge
key={platform.name}
variant="outline"
className="px-4 py-2 text-sm"
>
<Globe className="w-3 h-3 mr-2" />
{platform.name}
</Badge>
))}
</div>
</section>
{/* Features Grid */}
<section>
<h2 className="text-3xl font-bold text-center mb-4">Core Modules</h2>
<p className="text-center text-muted-foreground mb-12 max-w-2xl mx-auto">
Everything you need to build safe, compliant, cross-platform experiences
</p>
<div className="grid md:grid-cols-2 gap-6">
{features.map((feature) => (
<Card key={feature.title} className="p-6 hover:border-primary/50 transition-all">
<div className={`w-12 h-12 rounded-lg ${feature.bgColor} flex items-center justify-center mb-4`}>
<feature.icon className={`w-6 h-6 ${feature.color}`} />
</div>
<h3 className="text-xl font-semibold mb-2">{feature.title}</h3>
<p className="text-muted-foreground">{feature.description}</p>
</Card>
))}
</div>
</section>
{/* Code Examples */}
<section>
<h2 className="text-3xl font-bold text-center mb-4">Quick Examples</h2>
<p className="text-center text-muted-foreground mb-8 max-w-2xl mx-auto">
Get started in minutes with these production-ready code snippets
</p>
<Tabs defaultValue="passport" className="max-w-4xl mx-auto">
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="passport">Passport</TabsTrigger>
<TabsTrigger value="safeinput">SafeInput</TabsTrigger>
<TabsTrigger value="compliance">Compliance</TabsTrigger>
<TabsTrigger value="datasync">DataSync</TabsTrigger>
</TabsList>
<TabsContent value="passport" className="mt-6">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Users className="w-5 h-5 text-blue-500" />
Passport - Universal Identity
</CardTitle>
<CardDescription>
Authenticate users once, verify them everywhere
</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={codeExamples.passport} />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="safeinput" className="mt-6">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Shield className="w-5 h-5 text-green-500" />
SafeInput - PII Detection
</CardTitle>
<CardDescription>
Detect and scrub personally identifiable information automatically
</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={codeExamples.safeinput} />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="compliance" className="mt-6">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Lock className="w-5 h-5 text-purple-500" />
Compliance - COPPA/FERPA
</CardTitle>
<CardDescription>
Built-in compliance checks with audit trail logging
</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={codeExamples.compliance} />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="datasync" className="mt-6">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Zap className="w-5 h-5 text-yellow-500" />
DataSync - Cross-Platform State
</CardTitle>
<CardDescription>
Synchronize data across all supported platforms
</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={codeExamples.datasync} />
</CardContent>
</Card>
</TabsContent>
</Tabs>
</section>
{/* API Reference */}
<section>
<Card className="bg-gradient-to-br from-slate-800/50 to-purple-900/20 border-purple-500/20">
<CardContent className="p-8">
<div className="grid md:grid-cols-2 gap-8">
<div>
<h3 className="text-2xl font-bold mb-4">API Reference</h3>
<div className="space-y-4 text-sm">
<div>
<h4 className="font-semibold text-purple-400 mb-2">Passport</h4>
<ul className="space-y-1 text-muted-foreground">
<li><code className="text-xs bg-slate-800 px-1 rounded">new Passport(userId, username)</code> - Create passport</li>
<li><code className="text-xs bg-slate-800 px-1 rounded">verify()</code> - Verify identity</li>
<li><code className="text-xs bg-slate-800 px-1 rounded">syncAcross(platforms)</code> - Sync across platforms</li>
<li><code className="text-xs bg-slate-800 px-1 rounded">toJSON()</code> - Export as JSON</li>
</ul>
</div>
<div>
<h4 className="font-semibold text-green-400 mb-2">SafeInput</h4>
<ul className="space-y-1 text-muted-foreground">
<li><code className="text-xs bg-slate-800 px-1 rounded">SafeInput.detectPII(input)</code> - Detect PII types</li>
<li><code className="text-xs bg-slate-800 px-1 rounded">SafeInput.scrub(input)</code> - Scrub PII from string</li>
<li><code className="text-xs bg-slate-800 px-1 rounded">SafeInput.validate(input)</code> - Validate input safety</li>
</ul>
</div>
</div>
</div>
<div>
<div className="space-y-4 text-sm">
<div>
<h4 className="font-semibold text-yellow-400 mb-2">DataSync</h4>
<ul className="space-y-1 text-muted-foreground">
<li><code className="text-xs bg-slate-800 px-1 rounded">DataSync.sync(data, platforms)</code> - Sync data</li>
<li><code className="text-xs bg-slate-800 px-1 rounded">DataSync.pull(userId, platform)</code> - Pull data</li>
</ul>
</div>
<div>
<h4 className="font-semibold text-purple-400 mb-2">Compliance</h4>
<ul className="space-y-1 text-muted-foreground">
<li><code className="text-xs bg-slate-800 px-1 rounded">Compliance.isCOPPACompliant(age)</code> - Check if 13+</li>
<li><code className="text-xs bg-slate-800 px-1 rounded">Compliance.requiresParentConsent(age)</code> - Check if &lt;13</li>
<li><code className="text-xs bg-slate-800 px-1 rounded">Compliance.canCollectData(user)</code> - Check permission</li>
<li><code className="text-xs bg-slate-800 px-1 rounded">Compliance.logCheck(userId, type, result)</code> - Audit log</li>
</ul>
</div>
</div>
</div>
</div>
</CardContent>
</Card>
</section>
{/* Keywords/Use Cases */}
<section className="text-center">
<p className="text-sm text-muted-foreground mb-4">Built for</p>
<div className="flex flex-wrap justify-center gap-2">
{["metaverse", "cross-platform", "roblox", "uefn", "unity", "coppa", "compliance", "pii-detection"].map((keyword) => (
<Badge key={keyword} variant="secondary" className="px-3 py-1">
{keyword}
</Badge>
))}
</div>
</section>
{/* CTA */}
<section className="text-center space-y-6 py-8">
<h2 className="text-3xl font-bold">Ready to Build?</h2>
<p className="text-muted-foreground max-w-xl mx-auto">
Start building safer, compliant cross-platform experiences today.
</p>
<div className="flex gap-4 justify-center">
<Link to="/docs/lang/quickstart">
<Button size="lg">
Quick Start Guide
<ArrowRight className="w-4 h-4 ml-2" />
</Button>
</Link>
<Link to="/docs/lang">
<Button size="lg" variant="outline">
<FileText className="w-4 h-4 mr-2" />
Full Documentation
</Button>
</Link>
</div>
</section>
{/* Footer Info */}
<section className="text-center text-sm text-muted-foreground border-t border-border/50 pt-8">
<p>
Maintained by{" "}
<a href="https://aethex.dev" className="text-primary hover:underline">
AeThex Foundation
</a>
{" · "}
<a
href="https://github.com/AeThex-Corporation/AeThexOS/issues"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
Report Issues
</a>
</p>
</section>
</div>
</Layout>
);
}

View file

@ -67,9 +67,7 @@ await game.deploy(['roblox', 'fortnite', 'web']);`;
<span className="text-primary">Deploy Everywhere.</span>
</h1>
<p className="mt-6 text-lg text-muted-foreground sm:text-xl">
The complete developer platform for building cross-platform games
with AeThex. Ship to Roblox, Fortnite, Web, and Mobile from a
single codebase.
Ship to Roblox, Fortnite, Web, and Mobile from one codebase
</p>
<div className="mt-10 flex flex-col gap-4 sm:flex-row sm:justify-center">
<Link to="/docs/getting-started">
@ -118,9 +116,7 @@ await game.deploy(['roblox', 'fortnite', 'web']);`;
Simple. Powerful. Universal.
</h2>
<p className="text-lg text-muted-foreground">
Write your game logic once using the AeThex SDK, then deploy
to all major platforms with a single command. No
platform-specific code required.
Write once, deploy everywhere. No platform-specific code.
</p>
<ul className="space-y-3">
{[
@ -160,7 +156,7 @@ await game.deploy(['roblox', 'fortnite', 'web']);`;
<div className="text-center mb-12">
<h2 className="text-3xl font-bold">Everything You Need</h2>
<p className="text-lg text-muted-foreground mt-4">
Build production-ready games with enterprise-grade infrastructure
Enterprise-grade infrastructure
</p>
</div>
<div className="grid gap-8 md:grid-cols-2">
@ -185,7 +181,7 @@ await game.deploy(['roblox', 'fortnite', 'web']);`;
<div className="text-center mb-12">
<h2 className="text-3xl font-bold">Developer Tools</h2>
<p className="text-lg text-muted-foreground mt-4">
Everything you need to build, test, and deploy your games
Build, test, and deploy
</p>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">

View file

@ -110,13 +110,11 @@ export default function DocsApiReference() {
<ServerCog className="mr-2 h-3 w-3" />
API Reference
</Badge>
<h2 className="text-3xl font-semibold text-white">
Integrate programmatically with the AeThex API
<h2 className="text-2xl font-semibold text-white">
REST API reference and integration guide
</h2>
<p className="text-gray-300 max-w-3xl">
The REST API exposes every core capability of the AeThex platform.
Authenticate with OAuth 2.1 or personal access tokens, call idempotent
endpoints, and subscribe to webhooks to react to changes in real time.
Authenticate with OAuth or access tokens, call idempotent endpoints, and subscribe to webhooks for real-time updates.
</p>
</section>

View file

@ -88,14 +88,11 @@ export default function DocsCli() {
<Terminal className="mr-2 h-3 w-3" />
CLI Tools
</Badge>
<h2 className="text-3xl font-semibold text-white">
Operate AeThex from the command line
<h2 className="text-2xl font-semibold text-white">
Command-line tools for development and deployment
</h2>
<p className="text-gray-300 max-w-3xl">
The AeThex CLI automates local development, environment management,
and production deployments. It is built with stability in mind,
featuring transactional deploys, shell-friendly output, and native
support for Linux, macOS, and Windows.
Automate local development, environment management, and production deployments with cross-platform support.
</p>
</section>

View file

@ -70,7 +70,7 @@ const curriculumModules: CurriculumModule[] = [
id: "foundations",
title: "AeThex Foundations",
description:
"Establish core mastery of the AeThex platform, from environment setup to shipping your first interactive experience.",
"Master platform basics from setup to deployment.",
duration: "2.5 hrs",
level: "foundation",
focus: [
@ -129,7 +129,7 @@ const curriculumModules: CurriculumModule[] = [
id: "builder",
title: "Product Builder Track",
description:
"Design and scale collaborative communities with AeThex real-time tooling, automations, and membership flows.",
"Build collaborative communities with real-time tools and automations.",
duration: "3 hrs",
level: "builder",
focus: ["Community feed", "Workflow automations", "Admin control center"],
@ -184,7 +184,7 @@ const curriculumModules: CurriculumModule[] = [
id: "advanced",
title: "Advanced Ops & Ecosystems",
description:
"Engineer large-scale AeThex deployments that blend AI-guided creation, marketplace integrations, and monetization.",
"Scale deployments with AI, marketplace, and monetization features.",
duration: "3.5 hrs",
level: "advanced",
focus: ["AI pipelines", "Marketplace", "Monetization"],

View file

@ -22,7 +22,7 @@ const exampleSnippets = [
{
title: "Server-side matchmaking",
description:
"Quickly assemble a matchmaking service that uses AeThex queues, weighting rules, and player telemetry streams.",
"Build matchmaking with queues, weighting rules, and telemetry.",
language: "TypeScript",
href: "https://github.com/aethex/examples/tree/main/matchmaking-service",
code: `import { createQueue, matchPlayers } from "@aethex/matchmaking";
@ -54,7 +54,7 @@ export async function enqueuePlayer(player) {
{
title: "Realtime activity overlays",
description:
"Broadcast live deployment and incident updates to your in-game HUD or operations dashboard using AeThex events.",
"Broadcast deployment updates to in-game HUD or dashboards.",
language: "React",
href: "https://github.com/aethex/examples/tree/main/realtime-overlay",
code: `import { useEffect, useState } from "react";
@ -142,13 +142,11 @@ export default function DocsExamples() {
<Blocks className="mr-2 h-3 w-3" />
Examples & Templates
</Badge>
<h2 className="text-3xl font-semibold text-white">
Production-ready patterns you can copy
<h2 className="text-2xl font-semibold text-white">
Code examples and starter templates
</h2>
<p className="text-gray-300 max-w-3xl">
Explore curated examples covering backend services, realtime overlays,
automation scripts, and workflow integrations. Each project includes
detailed READMEs, infrastructure diagrams, and deployment runbooks.
Production-ready examples for backend services, real-time overlays, automation, and integrations.
</p>
</section>

View file

@ -58,14 +58,14 @@ const prerequisites = [
{
title: "AeThex Account",
description:
"You will need an active AeThex account to access the dashboard, API console, and deployment tools.",
"Active account required for dashboard and API access.",
actionLabel: "Create account",
actionHref: "/onboarding",
},
{
title: "Node.js 18+ & npm",
description:
"The AeThex CLI relies on modern Node runtimes. Verify your local toolchain before continuing.",
"Modern Node runtime required for CLI.",
actionLabel: "Verify environment",
actionHref: "https://nodejs.org/en/download",
},
@ -82,13 +82,13 @@ const setupSteps = [
{
title: "Install the CLI",
description:
"The CLI bootstraps local projects, provisions cloud environments, and manages deployments.",
"Bootstrap projects and manage deployments.",
command: "npm install -g aethex",
},
{
title: "Authenticate",
description:
"Log in with your AeThex credentials or paste a personal access token from the dashboard.",
"Log in with credentials or access token.",
command: "aethex login",
},
{
@ -196,8 +196,8 @@ export default function DocsGettingStarted() {
<Rocket className="mr-2 h-3 w-3" />
Getting Started
</Badge>
<h2 className="text-3xl font-semibold text-white">
Launch your first AeThex project in under 30 minutes
<h2 className="text-2xl font-semibold text-white">
Launch your first project in 30 minutes
</h2>
<p className="text-gray-300 max-w-3xl">
This guide walks through the minimum setup required to ship a

View file

@ -101,15 +101,11 @@ export default function DocsIntegrations() {
<Puzzle className="mr-2 h-3 w-3" />
Integrations
</Badge>
<h2 className="text-3xl font-semibold text-white">
Connecting partner services to AeThex
<h2 className="text-2xl font-semibold text-white">
Third-party integrations and connectors
</h2>
<p className="text-gray-300 max-w-3xl">
AeThex Integrations wrap third-party analytics, identity, payments,
and live-ops tooling behind a consistent runtime, security model, and
visual system. Use this guide to register new connectors, surface
partner UI in product flows, and automate data exchange without
hand-rolled plumbing.
Connect analytics, identity, payments, and live-ops tools with unified security and data exchange.
</p>
</section>
@ -135,7 +131,7 @@ export default function DocsIntegrations() {
</CardHeader>
<CardContent className="space-y-4">
<CardDescription className="text-gray-300">
Open-source MIT-licensed engine with GDScript and C# support
MIT-licensed engine with GDScript and C# support
</CardDescription>
<div className="flex flex-wrap gap-2">
<Badge variant="secondary" className="bg-blue-500/20 text-blue-200">GDScript</Badge>
@ -160,7 +156,7 @@ export default function DocsIntegrations() {
</CardHeader>
<CardContent className="space-y-4">
<CardDescription className="text-gray-300">
Powerful 2D engine with GML scripting for rapid game development
2D engine with GML scripting for rapid development
</CardDescription>
<div className="flex flex-wrap gap-2">
<Badge variant="secondary" className="bg-green-500/20 text-green-200">GML</Badge>

View file

@ -28,7 +28,7 @@ const platformPillars = [
{
title: "Unified dashboard",
description:
"Monitor deployments, live metrics, and release health from a single control surface. Jump into incidents, approvals, and audit trails without leaving the workspace.",
"Monitor deployments, metrics, and incidents from a unified dashboard.",
icon: LayoutDashboard,
href: "/dashboard",
cta: "Visit dashboard",
@ -36,7 +36,7 @@ const platformPillars = [
{
title: "AeThex Passport",
description:
"Give builders portable identity with verified skills, achievements, and cross-product progress synced to their Passport profile.",
"Portable identity with verified skills and achievements.",
icon: IdCard,
href: "/passport/me",
cta: "Open passport",
@ -169,14 +169,11 @@ export default function DocsPlatform() {
<Sparkles className="mr-2 h-3 w-3" />
Platform Experience
</Badge>
<h2 className="text-3xl font-semibold text-white">
Deliver cohesive player and builder journeys on AeThex
<h2 className="text-2xl font-semibold text-white">
Platform overview and core features
</h2>
<p className="text-gray-300 max-w-3xl">
Beyond deployment pipelines and CLI tooling, AeThex bundles
collaboration, identity, and live-ops systems so teams can craft
unforgettable experiences. Use this guide to orient new stakeholders
and plan end-to-end platform rollouts.
AeThex combines deployment pipelines, collaboration tools, identity systems, and live-ops features for building complete experiences.
</p>
</section>

View file

@ -0,0 +1,379 @@
import { Link } from "react-router-dom";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
Terminal,
CheckCircle2,
Copy,
ExternalLink,
Package,
} from "lucide-react";
import { useState } from "react";
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<button
onClick={handleCopy}
className="absolute top-3 right-3 p-1.5 rounded bg-slate-700 hover:bg-slate-600 transition-colors"
>
{copied ? <CheckCircle2 className="h-4 w-4 text-green-400" /> : <Copy className="h-4 w-4 text-slate-400" />}
</button>
);
}
function CodeBlock({ code, language = "bash" }: { code: string; language?: string }) {
return (
<div className="relative">
<CopyButton text={code} />
<pre className="bg-slate-900 border border-slate-700 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-slate-300 font-mono whitespace-pre">{code}</code>
</pre>
</div>
);
}
const installCode = `npm install -g @aethex.os/cli`;
const compileBasicCode = `aethex compile myfile.aethex`;
const compileTargetCode = `# JavaScript (default)
aethex compile myfile.aethex --target javascript
# Roblox/Lua
aethex compile myfile.aethex --target roblox
# UEFN/Verse (coming soon)
aethex compile myfile.aethex --target uefn
# Unity/C# (coming soon)
aethex compile myfile.aethex --target unity`;
const outputCode = `aethex compile myfile.aethex -o output.js
aethex compile myfile.aethex -t roblox -o game.lua`;
const watchCode = `aethex compile myfile.aethex --watch`;
const newProjectCode = `# Basic project
aethex new my-project
# With template
aethex new my-game --template passport`;
const initCode = `aethex init`;
const helloAethexCode = `reality HelloWorld {
platforms: all
}
journey Greet(name) {
platform: all
notify "Hello, " + name + "!"
}`;
const commands = [
{
name: "compile",
syntax: "aethex compile <file>",
description: "Compile an AeThex file to the target platform",
options: [
{ flag: "-t, --target <platform>", description: "Target platform (javascript, roblox, uefn, unity)" },
{ flag: "-o, --output <file>", description: "Output file path" },
{ flag: "-w, --watch", description: "Watch for changes and recompile" },
],
},
{
name: "new",
syntax: "aethex new <name>",
description: "Create a new AeThex project",
options: [
{ flag: "--template <type>", description: "Project template (basic, passport, game)" },
],
},
{
name: "init",
syntax: "aethex init",
description: "Initialize AeThex in the current directory",
options: [],
},
{
name: "--help",
syntax: "aethex --help",
description: "Show help information",
options: [],
},
{
name: "--version",
syntax: "aethex --version",
description: "Show CLI version",
options: [],
},
];
const targets = [
{ name: "javascript", language: "JavaScript", platform: "Web, Node.js", status: "ready" },
{ name: "roblox", language: "Lua", platform: "Roblox", status: "ready" },
{ name: "uefn", language: "Verse", platform: "Fortnite", status: "coming" },
{ name: "unity", language: "C#", platform: "Unity, VRChat", status: "coming" },
];
export default function DocsLangCli() {
return (
<div className="space-y-12">
{/* Header */}
<section>
<Badge className="mb-4 bg-green-500/20 text-green-400 border-green-500/30">
@aethex.os/cli
</Badge>
<h1 className="text-4xl font-bold mb-4">CLI Reference</h1>
<p className="text-xl text-muted-foreground">
AeThex Language Command Line Interface - Compile <code className="bg-slate-800 px-2 py-0.5 rounded">.aethex</code> files
to JavaScript, Lua, Verse, and C#.
</p>
</section>
{/* Installation */}
<section>
<h2 className="text-2xl font-bold mb-4">Installation</h2>
<CodeBlock code={installCode} />
<p className="mt-4 text-sm text-muted-foreground">
<a
href="https://www.npmjs.com/package/@aethex.os/cli"
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline inline-flex items-center gap-1"
>
View on npm <ExternalLink className="w-3 h-3" />
</a>
</p>
</section>
{/* Usage */}
<section>
<h2 className="text-2xl font-bold mb-6">Usage</h2>
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Terminal className="w-5 h-5" />
Compile a file
</CardTitle>
</CardHeader>
<CardContent>
<CodeBlock code={compileBasicCode} />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Compile to specific target</CardTitle>
</CardHeader>
<CardContent>
<CodeBlock code={compileTargetCode} />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Save to file</CardTitle>
</CardHeader>
<CardContent>
<CodeBlock code={outputCode} />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Watch mode</CardTitle>
<CardDescription>Auto-recompile on file changes</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={watchCode} />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Create new project</CardTitle>
</CardHeader>
<CardContent>
<CodeBlock code={newProjectCode} />
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Initialize in existing directory</CardTitle>
</CardHeader>
<CardContent>
<CodeBlock code={initCode} />
</CardContent>
</Card>
</div>
</section>
{/* Example */}
<section>
<h2 className="text-2xl font-bold mb-4">Example</h2>
<p className="text-muted-foreground mb-4">
Create <code className="bg-slate-800 px-2 py-0.5 rounded">hello.aethex</code>:
</p>
<CodeBlock code={helloAethexCode} language="aethex" />
<p className="text-muted-foreground mt-6 mb-4">Compile and run:</p>
<CodeBlock code={`aethex compile hello.aethex -o hello.js
node hello.js`} />
</section>
{/* Commands Reference */}
<section>
<h2 className="text-2xl font-bold mb-6">Commands</h2>
<div className="space-y-4">
{commands.map((cmd) => (
<Card key={cmd.name}>
<CardHeader className="pb-2">
<CardTitle className="font-mono text-lg">{cmd.syntax}</CardTitle>
<CardDescription>{cmd.description}</CardDescription>
</CardHeader>
{cmd.options.length > 0 && (
<CardContent>
<div className="space-y-2">
{cmd.options.map((opt) => (
<div key={opt.flag} className="flex gap-4 text-sm">
<code className="bg-slate-800 px-2 py-0.5 rounded whitespace-nowrap">{opt.flag}</code>
<span className="text-muted-foreground">{opt.description}</span>
</div>
))}
</div>
</CardContent>
)}
</Card>
))}
</div>
</section>
{/* Options */}
<section>
<h2 className="text-2xl font-bold mb-6">Global Options</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="border-b border-slate-700">
<th className="text-left py-3 px-4 font-medium">Option</th>
<th className="text-left py-3 px-4 font-medium">Description</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-slate-800">
<td className="py-3 px-4"><code className="bg-slate-800 px-2 py-0.5 rounded">-t, --target &lt;platform&gt;</code></td>
<td className="py-3 px-4 text-muted-foreground">Target platform (javascript, roblox, uefn, unity)</td>
</tr>
<tr className="border-b border-slate-800">
<td className="py-3 px-4"><code className="bg-slate-800 px-2 py-0.5 rounded">-o, --output &lt;file&gt;</code></td>
<td className="py-3 px-4 text-muted-foreground">Output file path</td>
</tr>
<tr className="border-b border-slate-800">
<td className="py-3 px-4"><code className="bg-slate-800 px-2 py-0.5 rounded">-w, --watch</code></td>
<td className="py-3 px-4 text-muted-foreground">Watch for changes</td>
</tr>
<tr className="border-b border-slate-800">
<td className="py-3 px-4"><code className="bg-slate-800 px-2 py-0.5 rounded">--template &lt;type&gt;</code></td>
<td className="py-3 px-4 text-muted-foreground">Project template (basic, passport, game)</td>
</tr>
</tbody>
</table>
</div>
</section>
{/* Targets */}
<section>
<h2 className="text-2xl font-bold mb-6">Targets</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="border-b border-slate-700">
<th className="text-left py-3 px-4 font-medium">Target</th>
<th className="text-left py-3 px-4 font-medium">Language</th>
<th className="text-left py-3 px-4 font-medium">Platform</th>
<th className="text-left py-3 px-4 font-medium">Status</th>
</tr>
</thead>
<tbody>
{targets.map((target) => (
<tr key={target.name} className="border-b border-slate-800">
<td className="py-3 px-4">
<code className="bg-slate-800 px-2 py-0.5 rounded">{target.name}</code>
</td>
<td className="py-3 px-4">{target.language}</td>
<td className="py-3 px-4 text-muted-foreground">{target.platform}</td>
<td className="py-3 px-4">
{target.status === "ready" ? (
<Badge className="bg-green-500/20 text-green-400 border-green-500/30">
<CheckCircle2 className="w-3 h-3 mr-1" /> Ready
</Badge>
) : (
<Badge variant="outline" className="text-slate-400">Coming Soon</Badge>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</section>
{/* Learn More */}
<section>
<h2 className="text-2xl font-bold mb-6">Learn More</h2>
<div className="grid md:grid-cols-3 gap-4">
<Link to="/docs/lang">
<Card className="h-full hover:border-primary/50 transition-all cursor-pointer">
<CardContent className="pt-6">
<Package className="w-6 h-6 mb-2 text-primary" />
<h3 className="font-semibold">Language Guide</h3>
<p className="text-sm text-muted-foreground">Full documentation</p>
</CardContent>
</Card>
</Link>
<Link to="/docs/lang/examples">
<Card className="h-full hover:border-primary/50 transition-all cursor-pointer">
<CardContent className="pt-6">
<Terminal className="w-6 h-6 mb-2 text-green-500" />
<h3 className="font-semibold">Examples</h3>
<p className="text-sm text-muted-foreground">Code samples</p>
</CardContent>
</Card>
</Link>
<a
href="https://www.npmjs.com/package/@aethex.os/core"
target="_blank"
rel="noopener noreferrer"
>
<Card className="h-full hover:border-primary/50 transition-all cursor-pointer">
<CardContent className="pt-6">
<Package className="w-6 h-6 mb-2 text-purple-500" />
<h3 className="font-semibold">@aethex.os/core</h3>
<p className="text-sm text-muted-foreground">Standard Library</p>
</CardContent>
</Card>
</a>
</div>
</section>
{/* Navigation */}
<section className="flex justify-between pt-8 border-t border-border/50">
<Link to="/docs/lang/syntax" className="text-sm text-muted-foreground hover:text-foreground">
Language Syntax
</Link>
<Link to="/docs/lang/examples" className="text-sm text-muted-foreground hover:text-foreground">
Examples
</Link>
</section>
</div>
);
}

View file

@ -0,0 +1,414 @@
import { Link } from "react-router-dom";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
CheckCircle2,
Copy,
Shield,
Users,
Award,
Zap,
Lock,
} from "lucide-react";
import { useState } from "react";
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<button
onClick={handleCopy}
className="absolute top-3 right-3 p-1.5 rounded bg-slate-700 hover:bg-slate-600 transition-colors"
>
{copied ? <CheckCircle2 className="h-4 w-4 text-green-400" /> : <Copy className="h-4 w-4 text-slate-400" />}
</button>
);
}
function CodeBlock({ code }: { code: string }) {
return (
<div className="relative">
<CopyButton text={code} />
<pre className="bg-slate-900 border border-slate-700 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-slate-300 font-mono whitespace-pre">{code}</code>
</pre>
</div>
);
}
const helloWorldCode = `# AeThex Hello World Example
reality HelloWorld {
platforms: all
}
journey Greet(name) {
platform: all
notify "Hello, " + name + " from AeThex!"
}`;
const crossPlatformAuthCode = `import { Passport, DataSync } from "@aethex.os/core"
reality UniversalAuth {
platforms: [roblox, uefn, web]
}
journey Login(username, password) {
platform: all
let passport = new Passport(username)
when passport.verify() {
sync passport across [roblox, uefn, web]
# Pull existing data from any platform
let playerData = DataSync.pull(passport.userId, "roblox")
notify "Logged in across all platforms!"
reveal passport
}
}`;
const secureLeaderboardCode = `# The Foundry Certification Exam
# Task: Build a COPPA-compliant, PII-safe leaderboard
#
# Requirements:
# 1. Must accept player scores
# 2. Must detect and block PII (phone numbers, emails, etc.)
# 3. Must work on Roblox (Lua)
# 4. Must display safely without exposing sensitive data
import { SafeInput, Compliance } from "@aethex.os/core"
reality SecureLeaderboard {
platforms: [roblox]
type: "compliance-exam"
}
# CRITICAL: This is the exam
# If PII gets through to the leaderboard, you FAIL
journey SubmitScore(player, playerName, score) {
platform: roblox
# STEP 1: Validate player age (COPPA compliance)
when !Compliance.isCOPPACompliant(player.age) {
notify "Players under 13 cannot submit scores publicly"
return
}
# STEP 2: Validate player name for PII
let nameValidation = SafeInput.validate(playerName)
when !nameValidation.valid {
notify "Invalid name: " + nameValidation.message
notify "Blocked PII types: " + nameValidation.blocked
# Log security incident
Compliance.logCheck(player.userId, "leaderboard_name_check", false)
return
}
# STEP 3: Validate score value for PII
let scoreValidation = SafeInput.validate(score.toString())
when !scoreValidation.valid {
notify "Invalid score: contains sensitive data"
# Log security incident
Compliance.logCheck(player.userId, "leaderboard_score_check", false)
return
}
# STEP 4: All validations passed - safe to submit
Compliance.logCheck(player.userId, "leaderboard_submission", true)
notify "Score submitted successfully!"
reveal {
player: nameValidation.clean,
score: scoreValidation.clean
}
}
# Test function: Attempts to inject PII
journey TestPIIDetection() {
platform: roblox
notify "=== FOUNDRY EXAM TEST SUITE ==="
# Test 1: Phone number in name
let test1 = SafeInput.validate("John 555-1234")
when test1.valid {
notify "❌ FAIL: Phone number not detected"
} otherwise {
notify "✅ PASS: Phone number blocked"
}
# Test 2: Email in name
let test2 = SafeInput.validate("player@email.com")
when test2.valid {
notify "❌ FAIL: Email not detected"
} otherwise {
notify "✅ PASS: Email blocked"
}
# Test 3: Clean name
let test3 = SafeInput.validate("PlayerOne")
when test3.valid {
notify "✅ PASS: Clean name accepted"
} otherwise {
notify "❌ FAIL: Clean name rejected"
}
# Test 4: SSN in score
let test4 = SafeInput.validate("123-45-6789")
when test4.valid {
notify "❌ FAIL: SSN not detected"
} otherwise {
notify "✅ PASS: SSN blocked"
}
}`;
const coppaRegistrationCode = `import { Compliance, Passport } from "@aethex.os/core"
journey RegisterUser(username, age) {
platform: all
when Compliance.isCOPPACompliant(age) {
# User is 13+, can proceed
let passport = new Passport(username)
passport.verify()
notify "Account created!"
} otherwise {
# Under 13, require parent consent
notify "Parent permission required"
# Send email to parent (implementation omitted)
}
}`;
const dataSyncCode = `import { Passport, DataSync } from "@aethex.os/core"
reality CrossPlatformProgress {
platforms: [roblox, uefn, web]
}
journey SaveProgress(player, progress) {
platform: all
# Sync progress data across all platforms
DataSync.sync({
level: progress.level,
experience: progress.xp,
inventory: progress.items
}, [roblox, uefn, web])
notify "Progress saved!"
}
journey LoadProgress(player) {
platform: all
# Pull latest progress from any platform
let data = DataSync.pull(player.userId, "web")
reveal data
}`;
const examples = [
{
id: "hello-world",
title: "Hello World",
description: "Your first AeThex program",
icon: Zap,
color: "text-yellow-500",
code: helloWorldCode,
difficulty: "Beginner",
},
{
id: "cross-platform-auth",
title: "Cross-Platform Authentication",
description: "Login once, authenticated everywhere",
icon: Users,
color: "text-blue-500",
code: crossPlatformAuthCode,
difficulty: "Intermediate",
},
{
id: "secure-leaderboard",
title: "Secure Leaderboard (Foundry Exam)",
description: "COPPA-compliant, PII-safe leaderboard - the certification exam",
icon: Award,
color: "text-purple-500",
code: secureLeaderboardCode,
difficulty: "Advanced",
},
{
id: "coppa-registration",
title: "COPPA-Compliant Registration",
description: "User registration with age verification",
icon: Lock,
color: "text-green-500",
code: coppaRegistrationCode,
difficulty: "Intermediate",
},
{
id: "data-sync",
title: "Cross-Platform Data Sync",
description: "Sync player progress across all platforms",
icon: Shield,
color: "text-cyan-500",
code: dataSyncCode,
difficulty: "Intermediate",
},
];
const difficultyColors: Record<string, string> = {
Beginner: "bg-green-500/20 text-green-400 border-green-500/30",
Intermediate: "bg-yellow-500/20 text-yellow-400 border-yellow-500/30",
Advanced: "bg-red-500/20 text-red-400 border-red-500/30",
};
export default function DocsLangExamples() {
const [activeExample, setActiveExample] = useState("hello-world");
const currentExample = examples.find((e) => e.id === activeExample) || examples[0];
return (
<div className="space-y-12">
{/* Header */}
<section>
<Badge className="mb-4 bg-purple-500/20 text-purple-400 border-purple-500/30">
Code Examples
</Badge>
<h1 className="text-4xl font-bold mb-4">Examples</h1>
<p className="text-xl text-muted-foreground">
Real-world code examples and patterns for AeThex development.
</p>
</section>
{/* Examples Grid for Quick Navigation */}
<section>
<h2 className="text-2xl font-bold mb-6">Browse Examples</h2>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
{examples.map((example) => (
<button
key={example.id}
onClick={() => setActiveExample(example.id)}
className={`text-left w-full ${
activeExample === example.id ? "ring-2 ring-primary" : ""
}`}
>
<Card className="h-full hover:border-primary/50 transition-all cursor-pointer">
<CardHeader>
<div className="flex items-start justify-between">
<example.icon className={`w-6 h-6 ${example.color}`} />
<Badge className={difficultyColors[example.difficulty]}>
{example.difficulty}
</Badge>
</div>
<CardTitle className="text-lg mt-2">{example.title}</CardTitle>
<CardDescription>{example.description}</CardDescription>
</CardHeader>
</Card>
</button>
))}
</div>
</section>
{/* Active Example Display */}
<section>
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<currentExample.icon className={`w-6 h-6 ${currentExample.color}`} />
<CardTitle>{currentExample.title}</CardTitle>
</div>
<Badge className={difficultyColors[currentExample.difficulty]}>
{currentExample.difficulty}
</Badge>
</div>
<CardDescription>{currentExample.description}</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={currentExample.code} />
</CardContent>
</Card>
</section>
{/* All Examples (Tabbed) */}
<section>
<h2 className="text-2xl font-bold mb-6">All Examples</h2>
<Tabs defaultValue="hello-world" className="w-full">
<TabsList className="flex flex-wrap h-auto gap-2">
{examples.map((example) => (
<TabsTrigger key={example.id} value={example.id} className="text-xs">
{example.title.split(" ")[0]}
</TabsTrigger>
))}
</TabsList>
{examples.map((example) => (
<TabsContent key={example.id} value={example.id} className="mt-6">
<Card>
<CardHeader>
<div className="flex items-center gap-3">
<example.icon className={`w-5 h-5 ${example.color}`} />
<CardTitle className="text-lg">{example.title}</CardTitle>
<Badge className={difficultyColors[example.difficulty]}>
{example.difficulty}
</Badge>
</div>
<CardDescription>{example.description}</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={example.code} />
</CardContent>
</Card>
</TabsContent>
))}
</Tabs>
</section>
{/* The Foundry Note */}
<section>
<Card className="bg-gradient-to-br from-slate-800/50 to-purple-900/20 border-purple-500/20">
<CardContent className="p-8">
<div className="flex items-start gap-4">
<Award className="w-8 h-8 text-purple-400 shrink-0" />
<div>
<h3 className="text-xl font-bold mb-2">The Foundry Certification</h3>
<p className="text-muted-foreground mb-4">
The <strong>Secure Leaderboard</strong> example above is the actual Foundry certification exam.
If you can implement a COPPA-compliant, PII-safe leaderboard that passes all validation tests,
you're ready for professional metaverse development.
</p>
<Link
to="/foundation"
className="text-primary hover:underline text-sm"
>
Learn more about The Foundry
</Link>
</div>
</div>
</CardContent>
</Card>
</section>
{/* Navigation */}
<section className="flex justify-between pt-8 border-t border-border/50">
<Link to="/docs/lang/cli" className="text-sm text-muted-foreground hover:text-foreground">
CLI Reference
</Link>
<Link to="/docs/lang" className="text-sm text-muted-foreground hover:text-foreground">
Back to Overview
</Link>
</section>
</div>
);
}

View file

@ -0,0 +1,380 @@
import { Link } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import {
Package,
Terminal,
BookOpen,
Code,
Zap,
Shield,
Users,
ExternalLink,
ArrowRight,
CheckCircle2,
FileText,
Github,
Globe,
Lock,
Copy,
} from "lucide-react";
import { useState } from "react";
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<button
onClick={handleCopy}
className="absolute top-3 right-3 p-1.5 rounded bg-slate-700 hover:bg-slate-600 transition-colors"
>
{copied ? <CheckCircle2 className="h-4 w-4 text-green-400" /> : <Copy className="h-4 w-4 text-slate-400" />}
</button>
);
}
function CodeBlock({ code, language = "aethex" }: { code: string; language?: string }) {
return (
<div className="relative">
<CopyButton text={code} />
<pre className="bg-slate-900 border border-slate-700 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-slate-300 font-mono whitespace-pre">{code}</code>
</pre>
</div>
);
}
const docSections = [
{
title: "Quick Start",
description: "Get up and running in 5 minutes",
icon: Zap,
href: "/docs/lang/quickstart",
color: "text-yellow-500",
bgColor: "bg-yellow-500/10",
},
{
title: "Language Syntax",
description: "Learn realities, journeys, and cross-platform sync",
icon: Code,
href: "/docs/lang/syntax",
color: "text-blue-500",
bgColor: "bg-blue-500/10",
},
{
title: "CLI Reference",
description: "Command line compiler and tools",
icon: Terminal,
href: "/docs/lang/cli",
color: "text-green-500",
bgColor: "bg-green-500/10",
},
{
title: "Examples",
description: "Real-world code examples and patterns",
icon: FileText,
href: "/docs/lang/examples",
color: "text-purple-500",
bgColor: "bg-purple-500/10",
},
];
const features = [
{
icon: Globe,
title: "Cross-Platform Native",
description: "Deploy to Roblox, UEFN, Unity, VRChat, Spatial, and Web",
},
{
icon: Users,
title: "Universal Passport",
description: "Single identity system across all metaverse platforms",
},
{
icon: Shield,
title: "Compliance-First",
description: "Built-in COPPA/FERPA/PII protection",
},
{
icon: Package,
title: "Standard Library",
description: "Battle-tested utilities for auth, data sync, and safety",
},
];
const platforms = [
{ name: "JavaScript", status: "ready" },
{ name: "Roblox (Lua)", status: "ready" },
{ name: "UEFN (Verse)", status: "coming" },
{ name: "Unity (C#)", status: "coming" },
];
const helloWorldCode = `reality HelloWorld {
platforms: all
}
journey Greet(name) {
platform: all
notify "Hello, " + name + "!"
}`;
const crossPlatformCode = `import { Passport } from "@aethex.os/core"
reality MyGame {
platforms: [roblox, uefn, web]
}
journey AuthenticatePlayer(username) {
platform: all
let passport = new Passport(username)
when passport.verify() {
sync passport across [roblox, uefn, web]
notify "Welcome, " + username + "!"
}
}`;
export default function DocsLangOverview() {
return (
<div className="space-y-12">
{/* Hero Section */}
<section className="text-center space-y-6">
<div className="flex items-center justify-center gap-3 mb-4">
<Badge className="text-sm px-4 py-1 bg-purple-500/20 text-purple-400 border-purple-500/30">
v1.0.0
</Badge>
<Badge variant="outline" className="text-sm px-4 py-1">
MIT License
</Badge>
</div>
<h1 className="text-4xl font-bold">AeThex Language</h1>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
<strong>Write once. Build everywhere. Comply by default.</strong>
</p>
<p className="text-muted-foreground max-w-3xl mx-auto">
AeThex is a programming language for cross-platform metaverse development.
Write your game logic, authentication, and compliance rules once, then compile
to JavaScript, Lua (Roblox), Verse (UEFN), and C# (Unity).
</p>
{/* Install Command */}
<div className="relative max-w-md mx-auto">
<div className="flex items-center gap-3 bg-slate-900 border border-slate-700 rounded-lg px-4 py-3">
<Terminal className="h-5 w-5 text-slate-500" />
<code className="text-sm font-mono text-slate-300 flex-1 text-left">
npm install -g @aethex.os/cli
</code>
<CopyButton text="npm install -g @aethex.os/cli" />
</div>
</div>
<div className="flex gap-4 justify-center pt-4">
<Link to="/docs/lang/quickstart">
<Button size="lg">
Get Started
<ArrowRight className="w-4 h-4 ml-2" />
</Button>
</Link>
<a
href="https://github.com/AeThex-Corporation/AeThexOS"
target="_blank"
rel="noopener noreferrer"
>
<Button size="lg" variant="outline">
<Github className="w-4 h-4 mr-2" />
GitHub
</Button>
</a>
</div>
</section>
{/* Platform Support */}
<section className="text-center">
<p className="text-sm text-muted-foreground mb-4">Compilation Targets</p>
<div className="flex flex-wrap justify-center gap-3">
{platforms.map((platform) => (
<Badge
key={platform.name}
variant={platform.status === "ready" ? "default" : "outline"}
className={`px-4 py-2 text-sm ${
platform.status === "ready"
? "bg-green-500/20 text-green-400 border-green-500/30"
: "text-slate-400"
}`}
>
{platform.status === "ready" && <CheckCircle2 className="w-3 h-3 mr-2" />}
{platform.name}
{platform.status === "coming" && " (Coming Soon)"}
</Badge>
))}
</div>
</section>
{/* Documentation Sections */}
<section>
<h2 className="text-2xl font-bold mb-6">Documentation</h2>
<div className="grid md:grid-cols-2 gap-4">
{docSections.map((section) => (
<Link key={section.title} to={section.href}>
<Card className="h-full hover:border-primary/50 transition-all cursor-pointer">
<CardHeader className="flex flex-row items-start gap-4">
<div className={`p-2 rounded-lg ${section.bgColor}`}>
<section.icon className={`w-5 h-5 ${section.color}`} />
</div>
<div>
<CardTitle className="text-lg">{section.title}</CardTitle>
<CardDescription>{section.description}</CardDescription>
</div>
</CardHeader>
</Card>
</Link>
))}
</div>
</section>
{/* Hello World Example */}
<section>
<h2 className="text-2xl font-bold mb-4">Hello World</h2>
<p className="text-muted-foreground mb-6">
Create <code className="bg-slate-800 px-2 py-0.5 rounded text-sm">hello.aethex</code>:
</p>
<CodeBlock code={helloWorldCode} />
<div className="mt-4 flex gap-2">
<code className="bg-slate-800 px-3 py-2 rounded text-sm font-mono">
aethex compile hello.aethex
</code>
<code className="bg-slate-800 px-3 py-2 rounded text-sm font-mono">
node hello.js
</code>
</div>
</section>
{/* Cross-Platform Example */}
<section>
<h2 className="text-2xl font-bold mb-4">Cross-Platform Authentication</h2>
<p className="text-muted-foreground mb-6">
One codebase, deployed everywhere:
</p>
<CodeBlock code={crossPlatformCode} />
</section>
{/* Features */}
<section>
<h2 className="text-2xl font-bold mb-6">Why AeThex?</h2>
<div className="grid md:grid-cols-2 gap-6">
{features.map((feature) => (
<div key={feature.title} className="flex gap-4">
<div className="p-2 h-fit rounded-lg bg-primary/10">
<feature.icon className="w-5 h-5 text-primary" />
</div>
<div>
<h3 className="font-semibold mb-1">{feature.title}</h3>
<p className="text-sm text-muted-foreground">{feature.description}</p>
</div>
</div>
))}
</div>
</section>
{/* npm Packages */}
<section>
<h2 className="text-2xl font-bold mb-6">npm Packages</h2>
<div className="grid md:grid-cols-2 gap-4">
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg">
<Terminal className="w-5 h-5 text-green-500" />
@aethex.os/cli
</CardTitle>
<CardDescription>Command line compiler</CardDescription>
</CardHeader>
<CardContent>
<a
href="https://www.npmjs.com/package/@aethex.os/cli"
target="_blank"
rel="noopener noreferrer"
className="text-sm text-primary hover:underline flex items-center gap-1"
>
View on npm <ExternalLink className="w-3 h-3" />
</a>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-lg">
<Package className="w-5 h-5 text-purple-500" />
@aethex.os/core
</CardTitle>
<CardDescription>Standard library</CardDescription>
</CardHeader>
<CardContent>
<a
href="https://www.npmjs.com/package/@aethex.os/core"
target="_blank"
rel="noopener noreferrer"
className="text-sm text-primary hover:underline flex items-center gap-1"
>
View on npm <ExternalLink className="w-3 h-3" />
</a>
</CardContent>
</Card>
</div>
</section>
{/* The Foundry */}
<section>
<Card className="bg-gradient-to-br from-slate-800/50 to-purple-900/20 border-purple-500/20">
<CardContent className="p-8 text-center">
<BookOpen className="w-12 h-12 mx-auto mb-4 text-purple-400" />
<h2 className="text-2xl font-bold mb-2">The Foundry Certification</h2>
<p className="text-muted-foreground mb-6 max-w-2xl mx-auto">
AeThex is the official language taught at The AeThex Foundry certification program.
Learn to build compliant, cross-platform metaverse experiences.
</p>
<div className="flex gap-4 justify-center">
<Link to="/foundation">
<Button>
Learn More
<ArrowRight className="w-4 h-4 ml-2" />
</Button>
</Link>
</div>
</CardContent>
</Card>
</section>
{/* Quick Links */}
<section className="text-center text-sm text-muted-foreground border-t border-border/50 pt-8">
<p className="flex items-center justify-center gap-4 flex-wrap">
<a
href="https://github.com/AeThex-Corporation/AeThexOS"
target="_blank"
rel="noopener noreferrer"
className="hover:text-foreground flex items-center gap-1"
>
<Github className="w-4 h-4" /> GitHub
</a>
<span></span>
<a
href="https://github.com/AeThex-Corporation/AeThexOS/issues"
target="_blank"
rel="noopener noreferrer"
className="hover:text-foreground"
>
Report Issues
</a>
<span></span>
<Link to="/community" className="hover:text-foreground">
Community
</Link>
</p>
</section>
</div>
);
}

View file

@ -0,0 +1,354 @@
import { Link } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import {
Terminal,
CheckCircle2,
Copy,
ArrowRight,
FileText,
Folder,
ExternalLink,
} from "lucide-react";
import { useState } from "react";
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<button
onClick={handleCopy}
className="absolute top-3 right-3 p-1.5 rounded bg-slate-700 hover:bg-slate-600 transition-colors"
>
{copied ? <CheckCircle2 className="h-4 w-4 text-green-400" /> : <Copy className="h-4 w-4 text-slate-400" />}
</button>
);
}
function CodeBlock({ code, language = "bash" }: { code: string; language?: string }) {
return (
<div className="relative">
<CopyButton text={code} />
<pre className="bg-slate-900 border border-slate-700 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-slate-300 font-mono whitespace-pre">{code}</code>
</pre>
</div>
);
}
function StepCard({ number, title, children }: { number: number; title: string; children: React.ReactNode }) {
return (
<Card className="relative overflow-hidden">
<div className="absolute top-4 left-4 w-8 h-8 rounded-full bg-primary/20 flex items-center justify-center">
<span className="text-sm font-bold text-primary">{number}</span>
</div>
<CardHeader className="pl-16">
<CardTitle className="text-lg">{title}</CardTitle>
</CardHeader>
<CardContent className="pl-16">
{children}
</CardContent>
</Card>
);
}
const installCode = `# Install the CLI globally
npm install -g @aethex.os/cli
# Verify installation
aethex --version`;
const newProjectCode = `aethex new my-first-game
cd my-first-game
npm install`;
const mainAethexCode = `reality MyFirstGame {
platforms: [roblox, web]
}
journey WelcomePlayer(username) {
platform: all
notify "Welcome, " + username + "!"
}`;
const compileCode = `# Compile to JavaScript
npm run build
# Run it
node build/main.js
# Or compile to Roblox
npm run build:roblox`;
const authExampleCode = `import { Passport } from "@aethex.os/core"
journey Login(username) {
let passport = new Passport(username)
when passport.verify() {
sync passport across [roblox, web]
notify "Logged in everywhere!"
}
}`;
const piiExampleCode = `import { SafeInput } from "@aethex.os/core"
journey SubmitScore(player, score) {
let validation = SafeInput.validate(score)
when validation.valid {
# Safe to submit
notify "Score: " + score
} otherwise {
# PII detected!
notify "Error: " + validation.message
}
}`;
const projectStructure = `my-project/
aethex.config.json # Config file
package.json # npm dependencies
src/
main.aethex # Your code
auth.aethex
game.aethex
build/
main.js # Compiled JavaScript
main.lua # Compiled Lua`;
const stdlibCode = `# Import from @aethex.os/core
import { Passport, DataSync, SafeInput, Compliance } from "@aethex.os/core"
# Import from @aethex.os/roblox (platform-specific)
import { RemoteEvent, Leaderboard } from "@aethex.os/roblox"`;
const commonPatterns = {
auth: `journey Login(user) {
when user.verify() {
sync user.passport across [roblox, web]
}
}`,
datasync: `journey SaveProgress(player) {
sync player.stats across [roblox, uefn, web]
}`,
pii: `let result = SafeInput.validate(userInput)
when result.valid {
# Safe to use
}`,
coppa: `when Compliance.isCOPPACompliant(user.age) {
# User is 13+
}`,
};
export default function DocsLangQuickstart() {
return (
<div className="space-y-12">
{/* Header */}
<section>
<Badge className="mb-4 bg-yellow-500/20 text-yellow-400 border-yellow-500/30">
5 Minute Guide
</Badge>
<h1 className="text-4xl font-bold mb-4">Quick Start</h1>
<p className="text-xl text-muted-foreground">
Get up and running with AeThex in 5 minutes.
</p>
</section>
{/* Installation */}
<section>
<h2 className="text-2xl font-bold mb-6">Installation</h2>
<CodeBlock code={installCode} />
</section>
{/* Steps */}
<section className="space-y-6">
<h2 className="text-2xl font-bold">Your First AeThex Program</h2>
<StepCard number={1} title="Create a new project">
<CodeBlock code={newProjectCode} />
</StepCard>
<StepCard number={2} title="Edit src/main.aethex">
<CodeBlock code={mainAethexCode} language="aethex" />
</StepCard>
<StepCard number={3} title="Compile and run">
<CodeBlock code={compileCode} />
</StepCard>
</section>
{/* Example Projects */}
<section>
<h2 className="text-2xl font-bold mb-6">Example Projects</h2>
<div className="space-y-6">
<Card>
<CardHeader>
<CardTitle>Cross-Platform Authentication</CardTitle>
<CardDescription>Authenticate users across multiple platforms with one codebase</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={authExampleCode} language="aethex" />
<div className="mt-4 text-sm text-muted-foreground">
Compile and run:
<code className="ml-2 bg-slate-800 px-2 py-1 rounded">aethex compile auth.aethex && node auth.js</code>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<div className="flex items-center gap-2">
<CardTitle>PII-Safe Leaderboard</CardTitle>
<Badge variant="outline" className="text-xs">Foundry Exam</Badge>
</div>
<CardDescription>
This is the Foundry certification exam - if you can build this correctly,
you're ready to work in metaverse development.
</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={piiExampleCode} language="aethex" />
</CardContent>
</Card>
</div>
</section>
{/* Compilation Targets */}
<section>
<h2 className="text-2xl font-bold mb-6">Compilation Targets</h2>
<CodeBlock code={`# JavaScript (default)
aethex compile game.aethex
# Roblox (Lua)
aethex compile game.aethex --target roblox --output game.lua
# UEFN (Verse) - Coming soon
aethex compile game.aethex --target uefn --output game.verse
# Unity (C#) - Coming soon
aethex compile game.aethex --target unity --output game.cs`} />
</section>
{/* Watch Mode */}
<section>
<h2 className="text-2xl font-bold mb-4">Watch Mode</h2>
<p className="text-muted-foreground mb-4">Auto-recompile on file save:</p>
<CodeBlock code="aethex compile game.aethex --watch" />
</section>
{/* Project Structure */}
<section>
<h2 className="text-2xl font-bold mb-4">Project Structure</h2>
<CodeBlock code={projectStructure} />
</section>
{/* Standard Library */}
<section>
<h2 className="text-2xl font-bold mb-4">Standard Library</h2>
<CodeBlock code={stdlibCode} language="aethex" />
</section>
{/* Common Patterns */}
<section>
<h2 className="text-2xl font-bold mb-6">Common Patterns</h2>
<div className="grid md:grid-cols-2 gap-4">
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Authentication</CardTitle>
</CardHeader>
<CardContent>
<CodeBlock code={commonPatterns.auth} language="aethex" />
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Data Sync</CardTitle>
</CardHeader>
<CardContent>
<CodeBlock code={commonPatterns.datasync} language="aethex" />
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">PII Protection</CardTitle>
</CardHeader>
<CardContent>
<CodeBlock code={commonPatterns.pii} language="aethex" />
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">COPPA Compliance</CardTitle>
</CardHeader>
<CardContent>
<CodeBlock code={commonPatterns.coppa} language="aethex" />
</CardContent>
</Card>
</div>
</section>
{/* Next Steps */}
<section>
<h2 className="text-2xl font-bold mb-6">Next Steps</h2>
<div className="grid md:grid-cols-2 gap-4">
<Link to="/docs/lang/syntax">
<Card className="h-full hover:border-primary/50 transition-all cursor-pointer">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<FileText className="w-5 h-5 text-blue-500" />
Language Syntax
</CardTitle>
<CardDescription>Learn realities, journeys, and more</CardDescription>
</CardHeader>
</Card>
</Link>
<Link to="/docs/lang/examples">
<Card className="h-full hover:border-primary/50 transition-all cursor-pointer">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Folder className="w-5 h-5 text-purple-500" />
Examples
</CardTitle>
<CardDescription>View more code examples</CardDescription>
</CardHeader>
</Card>
</Link>
</div>
</section>
{/* Getting Help */}
<section className="text-center text-sm text-muted-foreground border-t border-border/50 pt-8">
<h3 className="font-semibold text-foreground mb-4">Getting Help</h3>
<p className="flex items-center justify-center gap-4 flex-wrap">
<a
href="https://github.com/AeThex-Corporation/AeThexOS/issues"
target="_blank"
rel="noopener noreferrer"
className="hover:text-foreground flex items-center gap-1"
>
GitHub Issues <ExternalLink className="w-3 h-3" />
</a>
<span></span>
<a
href="https://discord.gg/aethex"
target="_blank"
rel="noopener noreferrer"
className="hover:text-foreground"
>
Discord
</a>
<span></span>
<Link to="/support" className="hover:text-foreground">
Support
</Link>
</p>
</section>
</div>
);
}

View file

@ -0,0 +1,365 @@
import { Link } from "react-router-dom";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import {
CheckCircle2,
Copy,
Code,
Layers,
Zap,
Globe,
GitBranch,
} from "lucide-react";
import { useState } from "react";
function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = async () => {
await navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<button
onClick={handleCopy}
className="absolute top-3 right-3 p-1.5 rounded bg-slate-700 hover:bg-slate-600 transition-colors"
>
{copied ? <CheckCircle2 className="h-4 w-4 text-green-400" /> : <Copy className="h-4 w-4 text-slate-400" />}
</button>
);
}
function CodeBlock({ code, language = "aethex" }: { code: string; language?: string }) {
return (
<div className="relative">
<CopyButton text={code} />
<pre className="bg-slate-900 border border-slate-700 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-slate-300 font-mono whitespace-pre">{code}</code>
</pre>
</div>
);
}
const realitiesCode = `reality GameName {
platforms: [roblox, uefn, web]
type: "multiplayer"
}`;
const journeysCode = `journey ProcessScore(player, score) {
platform: all
# Automatically scrubs PII before processing
when score > 1000 {
notify "High score achieved!"
}
}`;
const syncCode = `import { Passport } from "@aethex.os/core"
journey SaveProgress(player) {
platform: all
let passport = player.passport
sync passport across [roblox, uefn, web]
}`;
const conditionalCode = `when player.age < 13 {
# COPPA compliance automatic
notify "Parent permission required"
} otherwise {
# Full features unlocked
reveal player.stats
}`;
const platformSpecificCode = `journey DisplayLeaderboard() {
platform: roblox {
# Roblox-specific code
reveal leaderboardGUI
}
platform: web {
# Web-specific code
reveal leaderboardHTML
}
}`;
const coreLibraryCode = `import { Passport, DataSync, SafeInput, Compliance } from "@aethex.os/core"
# Passport - Universal identity
let passport = new Passport(userId, username)
passport.verify()
passport.syncAcross([roblox, web])
# DataSync - Cross-platform data
DataSync.sync(playerData, [roblox, uefn])
# SafeInput - PII protection
let result = SafeInput.validate(userInput)
when result.valid {
# Input is safe
}
# Compliance - COPPA/FERPA checks
when Compliance.isCOPPACompliant(user.age) {
# Can collect data
}`;
const robloxLibraryCode = `import { RemoteEvent, Leaderboard } from "@aethex.os/roblox"
# Roblox-specific features
let event = RemoteEvent.new("PlayerJoined")
event.FireAllClients(player)
let stats = Leaderboard.new("Points", 0)
Leaderboard.updateScore(player, "Points", 100)`;
const configCode = `{
"targets": ["javascript", "roblox", "uefn"],
"srcDir": "src",
"outDir": "build",
"stdlib": true,
"compliance": {
"coppa": true,
"ferpa": true,
"piiDetection": true
}
}`;
const projectStructureCode = `my-game/
aethex.config.json # Compilation settings
package.json # npm dependencies
src/
main.aethex # Entry point
auth.aethex # Authentication logic
game.aethex # Game logic
build/
main.js # JavaScript output
main.lua # Roblox output`;
const syntaxSections = [
{
id: "realities",
title: "Realities (Namespaces)",
icon: Layers,
description: "Define your game or application namespace",
code: realitiesCode,
},
{
id: "journeys",
title: "Journeys (Functions)",
icon: Zap,
description: "Create functions that run across platforms",
code: journeysCode,
},
{
id: "sync",
title: "Cross-Platform Sync",
icon: Globe,
description: "Synchronize data across all platforms with one line",
code: syncCode,
},
{
id: "conditionals",
title: "Conditional Logic",
icon: GitBranch,
description: "Use when/otherwise for conditions with built-in compliance",
code: conditionalCode,
},
{
id: "platform",
title: "Platform-Specific Code",
icon: Code,
description: "Write code that only runs on specific platforms",
code: platformSpecificCode,
},
];
export default function DocsLangSyntax() {
return (
<div className="space-y-12">
{/* Header */}
<section>
<Badge className="mb-4 bg-blue-500/20 text-blue-400 border-blue-500/30">
Language Reference
</Badge>
<h1 className="text-4xl font-bold mb-4">Language Syntax</h1>
<p className="text-xl text-muted-foreground">
Learn the AeThex syntax, from realities and journeys to cross-platform sync.
</p>
</section>
{/* Syntax Sections */}
<section className="space-y-8">
{syntaxSections.map((section) => (
<Card key={section.id} id={section.id}>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<section.icon className="w-5 h-5 text-primary" />
{section.title}
</CardTitle>
<CardDescription>{section.description}</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={section.code} />
</CardContent>
</Card>
))}
</section>
{/* Standard Library */}
<section>
<h2 className="text-2xl font-bold mb-6">Standard Library</h2>
<Tabs defaultValue="core" className="w-full">
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="core">@aethex.os/core</TabsTrigger>
<TabsTrigger value="roblox">@aethex.os/roblox</TabsTrigger>
</TabsList>
<TabsContent value="core" className="mt-6">
<Card>
<CardHeader>
<CardTitle>Core Library</CardTitle>
<CardDescription>
Universal utilities for authentication, data sync, and compliance
</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={coreLibraryCode} />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="roblox" className="mt-6">
<Card>
<CardHeader>
<CardTitle>Roblox Library</CardTitle>
<CardDescription>
Roblox-specific features and integrations
</CardDescription>
</CardHeader>
<CardContent>
<CodeBlock code={robloxLibraryCode} />
</CardContent>
</Card>
</TabsContent>
</Tabs>
</section>
{/* Configuration */}
<section>
<h2 className="text-2xl font-bold mb-4">Configuration</h2>
<p className="text-muted-foreground mb-6">
Configure your project with <code className="bg-slate-800 px-2 py-0.5 rounded text-sm">aethex.config.json</code>:
</p>
<CodeBlock code={configCode} language="json" />
</section>
{/* Project Structure */}
<section>
<h2 className="text-2xl font-bold mb-4">Project Structure</h2>
<CodeBlock code={projectStructureCode} />
</section>
{/* Compilation Targets Table */}
<section>
<h2 className="text-2xl font-bold mb-6">Compilation Targets</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="border-b border-slate-700">
<th className="text-left py-3 px-4 font-medium">Target</th>
<th className="text-left py-3 px-4 font-medium">Extension</th>
<th className="text-left py-3 px-4 font-medium">Use Case</th>
<th className="text-left py-3 px-4 font-medium">Status</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-slate-800">
<td className="py-3 px-4">JavaScript</td>
<td className="py-3 px-4"><code className="bg-slate-800 px-2 py-0.5 rounded text-sm">.js</code></td>
<td className="py-3 px-4 text-muted-foreground">Web applications, Node.js backends</td>
<td className="py-3 px-4"><Badge className="bg-green-500/20 text-green-400 border-green-500/30">Ready</Badge></td>
</tr>
<tr className="border-b border-slate-800">
<td className="py-3 px-4">Roblox (Lua)</td>
<td className="py-3 px-4"><code className="bg-slate-800 px-2 py-0.5 rounded text-sm">.lua</code></td>
<td className="py-3 px-4 text-muted-foreground">Roblox games</td>
<td className="py-3 px-4"><Badge className="bg-green-500/20 text-green-400 border-green-500/30">Ready</Badge></td>
</tr>
<tr className="border-b border-slate-800">
<td className="py-3 px-4">UEFN (Verse)</td>
<td className="py-3 px-4"><code className="bg-slate-800 px-2 py-0.5 rounded text-sm">.verse</code></td>
<td className="py-3 px-4 text-muted-foreground">Fortnite Creative</td>
<td className="py-3 px-4"><Badge variant="outline" className="text-slate-400">Coming Soon</Badge></td>
</tr>
<tr className="border-b border-slate-800">
<td className="py-3 px-4">Unity (C#)</td>
<td className="py-3 px-4"><code className="bg-slate-800 px-2 py-0.5 rounded text-sm">.cs</code></td>
<td className="py-3 px-4 text-muted-foreground">Unity games, VRChat</td>
<td className="py-3 px-4"><Badge variant="outline" className="text-slate-400">Coming Soon</Badge></td>
</tr>
</tbody>
</table>
</div>
</section>
{/* Keywords Reference */}
<section>
<h2 className="text-2xl font-bold mb-6">Keywords Reference</h2>
<div className="grid md:grid-cols-2 gap-4">
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Declarations</CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-sm">
<div><code className="bg-slate-800 px-2 py-0.5 rounded">reality</code> - Define a namespace</div>
<div><code className="bg-slate-800 px-2 py-0.5 rounded">journey</code> - Define a function</div>
<div><code className="bg-slate-800 px-2 py-0.5 rounded">let</code> - Declare a variable</div>
<div><code className="bg-slate-800 px-2 py-0.5 rounded">import</code> - Import from libraries</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Control Flow</CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-sm">
<div><code className="bg-slate-800 px-2 py-0.5 rounded">when</code> - Conditional (if)</div>
<div><code className="bg-slate-800 px-2 py-0.5 rounded">otherwise</code> - Else clause</div>
<div><code className="bg-slate-800 px-2 py-0.5 rounded">return</code> - Return from journey</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Cross-Platform</CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-sm">
<div><code className="bg-slate-800 px-2 py-0.5 rounded">sync ... across</code> - Sync data</div>
<div><code className="bg-slate-800 px-2 py-0.5 rounded">platform:</code> - Target platforms</div>
<div><code className="bg-slate-800 px-2 py-0.5 rounded">platforms:</code> - Reality platforms</div>
</CardContent>
</Card>
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-sm font-medium">Actions</CardTitle>
</CardHeader>
<CardContent className="space-y-2 text-sm">
<div><code className="bg-slate-800 px-2 py-0.5 rounded">notify</code> - Output message</div>
<div><code className="bg-slate-800 px-2 py-0.5 rounded">reveal</code> - Return/expose data</div>
<div><code className="bg-slate-800 px-2 py-0.5 rounded">new</code> - Create instance</div>
</CardContent>
</Card>
</div>
</section>
{/* Navigation */}
<section className="flex justify-between pt-8 border-t border-border/50">
<Link to="/docs/lang/quickstart" className="text-sm text-muted-foreground hover:text-foreground">
Quick Start
</Link>
<Link to="/docs/lang/cli" className="text-sm text-muted-foreground hover:text-foreground">
CLI Reference
</Link>
</section>
</div>
);
}

View file

@ -115,13 +115,12 @@ export default function OpportunitiesHub() {
<div className="text-center mb-8">
<div className="inline-flex items-center justify-center gap-2 mb-4">
<Briefcase className="h-8 w-8 text-cyan-400" />
<h1 className="text-4xl lg:text-5xl font-black text-white">
<h1 className="text-4xl font-bold text-white">
Opportunities
</h1>
</div>
<p className="text-lg text-gray-300 max-w-2xl mx-auto mb-6">
Find jobs, collaborations, and research opportunities across
all AeThex arms.
<p className="text-base text-gray-300 max-w-2xl mx-auto mb-6">
Find jobs and collaborations across AeThex
</p>
<div className="flex justify-center gap-3">
<Button

View file

@ -1038,6 +1038,211 @@ export function createServer() {
}
});
// =====================================================
// Foundation OAuth Callback Routes
// =====================================================
const FOUNDATION_URL = process.env.VITE_FOUNDATION_URL || "https://aethex.foundation";
const FOUNDATION_CLIENT_ID = process.env.FOUNDATION_OAUTH_CLIENT_ID || "aethex_corp";
const FOUNDATION_CLIENT_SECRET = process.env.FOUNDATION_OAUTH_CLIENT_SECRET;
const API_BASE = process.env.VITE_API_BASE || "https://aethex.dev";
// GET /auth/callback - Receives authorization code from Foundation
app.get("/auth/callback", async (req, res) => {
const { code, state, error, error_description } = req.query;
// Handle Foundation errors
if (error) {
const message = error_description
? decodeURIComponent(String(error_description))
: String(error);
return res.redirect(`/login?error=${error}&message=${encodeURIComponent(message)}`);
}
if (!code) {
return res.redirect(`/login?error=no_code&message=${encodeURIComponent("No authorization code received")}`);
}
try {
console.log("[Foundation OAuth] Received authorization code, initiating token exchange");
// Exchange code for token
if (!FOUNDATION_CLIENT_SECRET) {
throw new Error("FOUNDATION_OAUTH_CLIENT_SECRET not configured");
}
const tokenEndpoint = `${FOUNDATION_URL}/api/oauth/token`;
const params = new URLSearchParams();
params.append("grant_type", "authorization_code");
params.append("code", String(code));
params.append("client_id", FOUNDATION_CLIENT_ID);
params.append("client_secret", FOUNDATION_CLIENT_SECRET);
params.append("redirect_uri", `${API_BASE}/auth/callback`);
const tokenResponse = await fetch(tokenEndpoint, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params.toString(),
});
if (!tokenResponse.ok) {
const errorData = await tokenResponse.json().catch(() => ({}));
console.error("[Foundation OAuth] Token exchange failed:", errorData);
throw new Error(`Token exchange failed: ${tokenResponse.status}`);
}
const tokenData = await tokenResponse.json();
if (!tokenData.access_token) {
throw new Error("No access token in Foundation response");
}
// Fetch user info from Foundation
const userInfoResponse = await fetch(`${FOUNDATION_URL}/api/oauth/userinfo`, {
method: "GET",
headers: {
Authorization: `Bearer ${tokenData.access_token}`,
Accept: "application/json",
},
});
if (!userInfoResponse.ok) {
throw new Error(`Failed to fetch user info: ${userInfoResponse.status}`);
}
const userInfo = await userInfoResponse.json();
if (!userInfo.id || !userInfo.email) {
throw new Error("Invalid user info from Foundation");
}
console.log("[Foundation OAuth] User authenticated:", userInfo.id);
// Sync user to local database
const now = new Date().toISOString();
const cacheValidUntil = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
await adminSupabase.from("user_profiles").upsert({
id: userInfo.id,
email: userInfo.email,
username: userInfo.username || null,
full_name: userInfo.full_name || null,
avatar_url: userInfo.avatar_url || null,
profile_completed: userInfo.profile_complete || false,
foundation_synced_at: now,
cache_valid_until: cacheValidUntil,
updated_at: now,
});
// Set session cookies
res.cookie("foundation_access_token", tokenData.access_token, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: (tokenData.expires_in || 3600) * 1000,
});
res.cookie("auth_user_id", userInfo.id, {
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
});
// Redirect to dashboard or stored destination
const redirectTo = (req.query.redirect_to as string) || "/dashboard";
return res.redirect(redirectTo);
} catch (err: any) {
console.error("[Foundation OAuth] Callback error:", err);
const message = err?.message || "Authentication failed";
return res.redirect(`/login?error=auth_failed&message=${encodeURIComponent(message)}`);
}
});
// POST /auth/callback/exchange - Exchange code for token (called from frontend)
app.post("/auth/callback/exchange", async (req, res) => {
const { code } = req.body || {};
if (!code) {
return res.status(400).json({ error: "Authorization code is required" });
}
try {
if (!FOUNDATION_CLIENT_SECRET) {
throw new Error("FOUNDATION_OAUTH_CLIENT_SECRET not configured");
}
const tokenEndpoint = `${FOUNDATION_URL}/api/oauth/token`;
const params = new URLSearchParams();
params.append("grant_type", "authorization_code");
params.append("code", code);
params.append("client_id", FOUNDATION_CLIENT_ID);
params.append("client_secret", FOUNDATION_CLIENT_SECRET);
params.append("redirect_uri", `${API_BASE}/auth/callback`);
const tokenResponse = await fetch(tokenEndpoint, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params.toString(),
});
if (!tokenResponse.ok) {
const errorData = await tokenResponse.json().catch(() => ({}));
throw new Error(`Token exchange failed: ${tokenResponse.status}`);
}
const tokenData = await tokenResponse.json();
if (!tokenData.access_token) {
throw new Error("No access token in Foundation response");
}
// Fetch user info from Foundation
const userInfoResponse = await fetch(`${FOUNDATION_URL}/api/oauth/userinfo`, {
method: "GET",
headers: {
Authorization: `Bearer ${tokenData.access_token}`,
Accept: "application/json",
},
});
if (!userInfoResponse.ok) {
throw new Error(`Failed to fetch user info: ${userInfoResponse.status}`);
}
const userInfo = await userInfoResponse.json();
// Sync user to local database
const now = new Date().toISOString();
const cacheValidUntil = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
await adminSupabase.from("user_profiles").upsert({
id: userInfo.id,
email: userInfo.email,
username: userInfo.username || null,
full_name: userInfo.full_name || null,
avatar_url: userInfo.avatar_url || null,
profile_completed: userInfo.profile_complete || false,
foundation_synced_at: now,
cache_valid_until: cacheValidUntil,
updated_at: now,
});
// Set session cookies
res.cookie("foundation_access_token", tokenData.access_token, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: (tokenData.expires_in || 3600) * 1000,
});
res.cookie("auth_user_id", userInfo.id, {
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
maxAge: 30 * 24 * 60 * 60 * 1000,
});
console.log("[Foundation OAuth] Token exchange successful for:", userInfo.id);
return res.json({ accessToken: tokenData.access_token, user: userInfo });
} catch (err: any) {
console.error("[Foundation OAuth] Token exchange error:", err);
return res.status(400).json({ error: err?.message || "Token exchange failed" });
}
});
// Admin-backed API (service role)
try {
const ownerEmail = (

View file

@ -109,14 +109,14 @@ CREATE TABLE notifications (
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Insert default achievements
INSERT INTO achievements (name, description, icon, xp_reward, badge_color) VALUES
('Welcome to AeThex', 'Complete your profile setup', '🎉', 100, '#10B981'),
('First Project', 'Create your first project', '🚀', 150, '#3B82F6'),
('Community Contributor', 'Make your first community post', '💬', 75, '#8B5CF6'),
('Level Up', 'Reach level 5', '', 200, '#F59E0B'),
('Experienced Developer', 'Complete 5 projects', '👨‍💻', 300, '#EF4444'),
('Community Leader', 'Get 100 likes on your posts', '👑', 500, '#F97316');
-- Insert core achievements with deterministic UUIDs to match activate.ts
INSERT INTO achievements (id, name, description, icon, xp_reward, badge_color) VALUES
('b6e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'Welcome to AeThex', 'Completed onboarding and joined the AeThex network.', '🎉', 250, '#7C3AED'),
('c1e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'AeThex Explorer', 'Engaged with community initiatives and posted first update.', '🧭', 400, '#0EA5E9'),
('d1e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'Community Champion', 'Contributed feedback, resolved bugs, and mentored squads.', '🏆', 750, '#22C55E'),
('e1e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'Workshop Architect', 'Published a high-impact mod or toolkit adopted by teams.', '🛠️', 1200, '#F97316'),
('f1e2e1e2-2e2e-5e2e-8e2e-e2e2e2e2e2e2', 'GOD Mode', 'Legendary status awarded by AeThex studio leadership.', '', 5000, '#FACC15');
-- Enable Row Level Security (RLS)
ALTER TABLE user_profiles ENABLE ROW LEVEL SECURITY;

View file

@ -1 +1 @@
v2.67.1
v2.75.0

View file

@ -47,19 +47,14 @@ CREATE INDEX IF NOT EXISTS idx_user_profiles_stripe_customer ON user_profiles(st
ALTER TABLE badges ENABLE ROW LEVEL SECURITY;
ALTER TABLE user_badges ENABLE ROW LEVEL SECURITY;
-- 7. RLS Policies for badges (read-only for authenticated users)
CREATE POLICY IF NOT EXISTS "Badges are viewable by everyone"
ON badges FOR SELECT
USING (true);
DROP POLICY IF EXISTS "Badges are viewable by everyone" ON badges;
CREATE POLICY "Badges are viewable by everyone" ON badges FOR SELECT USING (true);
-- 8. RLS Policies for user_badges
CREATE POLICY IF NOT EXISTS "Users can view their own badges"
ON user_badges FOR SELECT
USING (auth.uid() = user_id);
DROP POLICY IF EXISTS "Users can view their own badges" ON user_badges;
CREATE POLICY "Users can view their own badges" ON user_badges FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY IF NOT EXISTS "Users can view others badges"
ON user_badges FOR SELECT
USING (true);
DROP POLICY IF EXISTS "Users can view others badges" ON user_badges;
CREATE POLICY "Users can view others badges" ON user_badges FOR SELECT USING (true);
-- 9. Seed initial badges that unlock AI personas
INSERT INTO badges (name, slug, description, icon, unlock_criteria, unlocks_persona) VALUES

View file

@ -36,6 +36,7 @@ CREATE INDEX IF NOT EXISTS idx_discord_linking_sessions_token ON discord_linking
CREATE INDEX IF NOT EXISTS idx_discord_linking_sessions_expires ON discord_linking_sessions(expires_at);
ALTER TABLE discord_linking_sessions ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "discord_linking_sessions_service_role" ON discord_linking_sessions;
CREATE POLICY "discord_linking_sessions_service_role" ON discord_linking_sessions
FOR ALL TO service_role USING (true);
@ -73,35 +74,42 @@ CREATE INDEX IF NOT EXISTS idx_discord_user_roles_server ON discord_user_roles(s
-- RLS Policies
ALTER TABLE discord_links ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "discord_links_users_select" ON discord_links;
CREATE POLICY "discord_links_users_select" ON discord_links
FOR SELECT TO authenticated
USING (user_id = auth.uid());
DROP POLICY IF EXISTS "discord_links_service_role" ON discord_links;
CREATE POLICY "discord_links_service_role" ON discord_links
FOR ALL TO service_role
USING (true);
ALTER TABLE discord_verifications ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "discord_verifications_service_role" ON discord_verifications;
CREATE POLICY "discord_verifications_service_role" ON discord_verifications
FOR ALL TO service_role
USING (true);
ALTER TABLE discord_role_mappings ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "discord_role_mappings_public_read" ON discord_role_mappings;
CREATE POLICY "discord_role_mappings_public_read" ON discord_role_mappings
FOR SELECT
USING (true);
DROP POLICY IF EXISTS "discord_role_mappings_admin_write" ON discord_role_mappings;
CREATE POLICY "discord_role_mappings_admin_write" ON discord_role_mappings
FOR INSERT
TO service_role
WITH CHECK (true);
DROP POLICY IF EXISTS "discord_role_mappings_admin_update" ON discord_role_mappings;
CREATE POLICY "discord_role_mappings_admin_update" ON discord_role_mappings
FOR UPDATE
TO service_role
USING (true);
ALTER TABLE discord_user_roles ENABLE ROW LEVEL SECURITY;
DROP POLICY IF EXISTS "discord_user_roles_service_role" ON discord_user_roles;
CREATE POLICY "discord_user_roles_service_role" ON discord_user_roles
FOR ALL TO service_role
USING (true);

View file

@ -94,28 +94,32 @@ ALTER TABLE game_sessions ENABLE ROW LEVEL SECURITY;
ALTER TABLE roblox_links ENABLE ROW LEVEL SECURITY;
ALTER TABLE web3_wallets ENABLE ROW LEVEL SECURITY;
-- Public tables for game auth (service role only for inserts)
DROP POLICY IF EXISTS "game_auth_tokens_service_insert" ON game_auth_tokens;
CREATE POLICY "game_auth_tokens_service_insert" ON game_auth_tokens
FOR INSERT TO anon, authenticated
WITH CHECK (false);
DROP POLICY IF EXISTS "game_sessions_service_insert" ON game_sessions;
CREATE POLICY "game_sessions_service_insert" ON game_sessions
FOR INSERT TO anon, authenticated
WITH CHECK (false);
-- Allow authenticated users to view their own game data
DROP POLICY IF EXISTS "game_auth_tokens_user_select" ON game_auth_tokens;
CREATE POLICY "game_auth_tokens_user_select" ON game_auth_tokens
FOR SELECT TO authenticated
USING (user_id = auth.uid());
DROP POLICY IF EXISTS "game_sessions_user_select" ON game_sessions;
CREATE POLICY "game_sessions_user_select" ON game_sessions
FOR SELECT TO authenticated
USING (user_id = auth.uid());
DROP POLICY IF EXISTS "roblox_links_user_select" ON roblox_links;
CREATE POLICY "roblox_links_user_select" ON roblox_links
FOR SELECT TO authenticated
USING (user_id = auth.uid());
DROP POLICY IF EXISTS "web3_wallets_user_select" ON web3_wallets;
CREATE POLICY "web3_wallets_user_select" ON web3_wallets
FOR SELECT TO authenticated
USING (user_id = auth.uid());

View file

@ -48,22 +48,25 @@ ALTER TABLE fourthwall_products ENABLE ROW LEVEL SECURITY;
ALTER TABLE fourthwall_orders ENABLE ROW LEVEL SECURITY;
ALTER TABLE fourthwall_webhook_logs ENABLE ROW LEVEL SECURITY;
-- Create RLS policies - allow authenticated users to read, admins to manage
DROP POLICY IF EXISTS "Allow authenticated users to read fourthwall products" ON fourthwall_products;
CREATE POLICY "Allow authenticated users to read fourthwall products"
ON fourthwall_products
FOR SELECT
USING (true);
DROP POLICY IF EXISTS "Allow service role to manage fourthwall products" ON fourthwall_products;
CREATE POLICY "Allow service role to manage fourthwall products"
ON fourthwall_products
FOR ALL
USING (auth.role() = 'service_role');
DROP POLICY IF EXISTS "Allow service role to manage fourthwall orders" ON fourthwall_orders;
CREATE POLICY "Allow service role to manage fourthwall orders"
ON fourthwall_orders
FOR ALL
USING (auth.role() = 'service_role');
DROP POLICY IF EXISTS "Allow service role to manage webhook logs" ON fourthwall_webhook_logs;
CREATE POLICY "Allow service role to manage webhook logs"
ON fourthwall_webhook_logs
FOR ALL

View file

@ -44,27 +44,27 @@ GRANT SELECT, INSERT, UPDATE, DELETE ON public.provider_identities TO service_ro
-- Enable RLS
ALTER TABLE public.provider_identities ENABLE ROW LEVEL SECURITY;
-- Users can only see their own provider identities
DROP POLICY IF EXISTS "Users can view own provider identities" ON public.provider_identities;
CREATE POLICY "Users can view own provider identities"
ON public.provider_identities FOR SELECT
USING (auth.uid() = user_id);
-- Users can only insert their own provider identities
DROP POLICY IF EXISTS "Users can insert own provider identities" ON public.provider_identities;
CREATE POLICY "Users can insert own provider identities"
ON public.provider_identities FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Users can only update their own provider identities
DROP POLICY IF EXISTS "Users can update own provider identities" ON public.provider_identities;
CREATE POLICY "Users can update own provider identities"
ON public.provider_identities FOR UPDATE
USING (auth.uid() = user_id);
-- Users can only delete their own provider identities
DROP POLICY IF EXISTS "Users can delete own provider identities" ON public.provider_identities;
CREATE POLICY "Users can delete own provider identities"
ON public.provider_identities FOR DELETE
USING (auth.uid() = user_id);
-- Service role can do anything for OAuth flows
DROP POLICY IF EXISTS "Service role can manage all provider identities" ON public.provider_identities;
CREATE POLICY "Service role can manage all provider identities"
ON public.provider_identities
FOR ALL

View file

@ -47,17 +47,19 @@ ALTER TABLE public.collaboration_posts_authors ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.collaboration_post_likes ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.collaboration_comments ENABLE ROW LEVEL SECURITY;
-- Policies for collaboration_posts
DROP POLICY IF EXISTS "collaboration_posts_read" ON public.collaboration_posts;
CREATE POLICY "collaboration_posts_read" ON public.collaboration_posts
FOR SELECT TO authenticated USING (is_published = true);
DROP POLICY IF EXISTS "collaboration_posts_manage_own" ON public.collaboration_posts;
CREATE POLICY "collaboration_posts_manage_own" ON public.collaboration_posts
FOR ALL TO authenticated USING (created_by = auth.uid()) WITH CHECK (created_by = auth.uid());
-- Policies for collaboration_posts_authors
DROP POLICY IF EXISTS "collaboration_posts_authors_read" ON public.collaboration_posts_authors;
CREATE POLICY "collaboration_posts_authors_read" ON public.collaboration_posts_authors
FOR SELECT TO authenticated USING (true);
DROP POLICY IF EXISTS "collaboration_posts_authors_manage" ON public.collaboration_posts_authors;
CREATE POLICY "collaboration_posts_authors_manage" ON public.collaboration_posts_authors
FOR ALL TO authenticated
USING (
@ -73,17 +75,19 @@ CREATE POLICY "collaboration_posts_authors_manage" ON public.collaboration_posts
)
);
-- Policies for collaboration_post_likes
DROP POLICY IF EXISTS "collaboration_post_likes_read" ON public.collaboration_post_likes;
CREATE POLICY "collaboration_post_likes_read" ON public.collaboration_post_likes
FOR SELECT TO authenticated USING (true);
DROP POLICY IF EXISTS "collaboration_post_likes_manage_self" ON public.collaboration_post_likes;
CREATE POLICY "collaboration_post_likes_manage_self" ON public.collaboration_post_likes
FOR ALL TO authenticated USING (user_id = auth.uid()) WITH CHECK (user_id = auth.uid());
-- Policies for collaboration_comments
DROP POLICY IF EXISTS "collaboration_comments_read" ON public.collaboration_comments;
CREATE POLICY "collaboration_comments_read" ON public.collaboration_comments
FOR SELECT TO authenticated USING (true);
DROP POLICY IF EXISTS "collaboration_comments_manage_self" ON public.collaboration_comments;
CREATE POLICY "collaboration_comments_manage_self" ON public.collaboration_comments
FOR ALL TO authenticated USING (user_id = auth.uid()) WITH CHECK (user_id = auth.uid());

View file

@ -23,11 +23,11 @@ CREATE INDEX IF NOT EXISTS idx_user_followed_arms_arm_id ON public.user_followed
-- Enable RLS on user_followed_arms
ALTER TABLE public.user_followed_arms ENABLE ROW LEVEL SECURITY;
-- Policy: Users can read all followed arms data
DROP POLICY IF EXISTS "user_followed_arms_read" ON public.user_followed_arms;
CREATE POLICY "user_followed_arms_read" ON public.user_followed_arms
FOR SELECT TO authenticated USING (true);
-- Policy: Users can manage their own followed arms
DROP POLICY IF EXISTS "user_followed_arms_manage_self" ON public.user_followed_arms;
CREATE POLICY "user_followed_arms_manage_self" ON public.user_followed_arms
FOR ALL TO authenticated USING (user_id = auth.uid()) WITH CHECK (user_id = auth.uid());

View file

@ -54,18 +54,18 @@ ALTER TABLE staff_contractors ENABLE ROW LEVEL SECURITY;
-- Staff members policies
-- Allow authenticated users to read all staff members (directory)
DROP POLICY IF EXISTS "staff_members_select_authenticated" ON staff_members;
CREATE POLICY "staff_members_select_authenticated" ON staff_members
FOR SELECT
USING (auth.role() = 'authenticated');
-- Allow staff members to update their own record
DROP POLICY IF EXISTS "staff_members_update_own" ON staff_members;
CREATE POLICY "staff_members_update_own" ON staff_members
FOR UPDATE
USING (auth.uid() = user_id OR auth.role() = 'service_role')
WITH CHECK (auth.uid() = user_id OR auth.role() = 'service_role');
-- Allow admins to do anything
DROP POLICY IF EXISTS "staff_members_admin_all" ON staff_members;
CREATE POLICY "staff_members_admin_all" ON staff_members
FOR ALL
USING (
@ -79,18 +79,18 @@ CREATE POLICY "staff_members_admin_all" ON staff_members
-- Staff contractors policies
-- Allow authenticated users to read all contractors (directory)
DROP POLICY IF EXISTS "staff_contractors_select_authenticated" ON staff_contractors;
CREATE POLICY "staff_contractors_select_authenticated" ON staff_contractors
FOR SELECT
USING (auth.role() = 'authenticated');
-- Allow contractors to update their own record
DROP POLICY IF EXISTS "staff_contractors_update_own" ON staff_contractors;
CREATE POLICY "staff_contractors_update_own" ON staff_contractors
FOR UPDATE
USING (auth.uid() = user_id OR auth.role() = 'service_role')
WITH CHECK (auth.uid() = user_id OR auth.role() = 'service_role');
-- Allow admins to do anything
DROP POLICY IF EXISTS "staff_contractors_admin_all" ON staff_contractors;
CREATE POLICY "staff_contractors_admin_all" ON staff_contractors
FOR ALL
USING (

View file

@ -18,7 +18,7 @@ CREATE INDEX idx_user_email_links_primary ON user_email_links(user_id, is_primar
-- Enable RLS
ALTER TABLE user_email_links ENABLE ROW LEVEL SECURITY;
-- RLS: Users can view their own linked emails
DROP POLICY IF EXISTS "Users can view own email links" ON user_email_links;
CREATE POLICY "Users can view own email links"
ON user_email_links
FOR SELECT
@ -29,7 +29,7 @@ CREATE POLICY "Users can view own email links"
)
);
-- RLS: Service role can do anything (for backend operations)
DROP POLICY IF EXISTS "Service role full access" ON user_email_links;
CREATE POLICY "Service role full access"
ON user_email_links
FOR ALL

View file

@ -86,33 +86,45 @@ alter table public.ethos_artist_profiles enable row level security;
alter table public.ethos_guild_members enable row level security;
alter table public.ethos_licensing_agreements enable row level security;
-- RLS Policies: ethos_tracks
drop policy if exists "Ethos tracks are readable by all authenticated users" on public.ethos_tracks;
create policy "Ethos tracks are readable by all authenticated users" on public.ethos_tracks
for select using (auth.role() = 'authenticated');
create policy "Users can insert their own tracks" on public.ethos_tracks
drop policy if exists "Users can insert their own tracks" on public.ethos_tracks;
create policy "Users can insert their own tracks" on public.ethos_tracks
for insert with check (auth.uid() = user_id);
create policy "Users can update their own tracks" on public.ethos_tracks
drop policy if exists "Users can update their own tracks" on public.ethos_tracks;
create policy "Users can update their own tracks" on public.ethos_tracks
for update using (auth.uid() = user_id);
create policy "Users can delete their own tracks" on public.ethos_tracks
drop policy if exists "Users can delete their own tracks" on public.ethos_tracks;
create policy "Users can delete their own tracks" on public.ethos_tracks
for delete using (auth.uid() = user_id);
-- RLS Policies: ethos_artist_profiles
drop policy if exists "Ethos artist profiles are readable by all authenticated users" on public.ethos_artist_profiles;
create policy "Ethos artist profiles are readable by all authenticated users" on public.ethos_artist_profiles
for select using (auth.role() = 'authenticated');
create policy "Users can insert their own artist profile" on public.ethos_artist_profiles
drop policy if exists "Users can insert their own artist profile" on public.ethos_artist_profiles;
create policy "Users can insert their own artist profile" on public.ethos_artist_profiles
for insert with check (auth.uid() = user_id);
create policy "Users can update their own artist profile" on public.ethos_artist_profiles
drop policy if exists "Users can update their own artist profile" on public.ethos_artist_profiles;
create policy "Users can update their own artist profile" on public.ethos_artist_profiles
for update using (auth.uid() = user_id);
-- RLS Policies: ethos_guild_members
drop policy if exists "Guild membership is readable by all authenticated users" on public.ethos_guild_members;
create policy "Guild membership is readable by all authenticated users" on public.ethos_guild_members
for select using (auth.role() = 'authenticated');
create policy "Admins can manage guild members" on public.ethos_guild_members
drop policy if exists "Admins can manage guild members" on public.ethos_guild_members;
create policy "Admins can manage guild members" on public.ethos_guild_members
for all using (
exists(
@ -121,10 +133,12 @@ create policy "Admins can manage guild members" on public.ethos_guild_members
)
);
create policy "Users can see their own membership" on public.ethos_guild_members
drop policy if exists "Users can see their own membership" on public.ethos_guild_members;
create policy "Users can see their own membership" on public.ethos_guild_members
for select using (auth.uid() = user_id or auth.role() = 'authenticated');
-- RLS Policies: ethos_licensing_agreements
drop policy if exists "Licensing agreements readable by involved parties" on public.ethos_licensing_agreements;
create policy "Licensing agreements readable by involved parties" on public.ethos_licensing_agreements
for select using (
auth.uid() in (

View file

@ -43,9 +43,13 @@ alter table public.ethos_verification_requests enable row level security;
alter table public.ethos_verification_audit_log enable row level security;
-- RLS Policies: ethos_verification_requests
create policy "Artists can view their own verification request" on public.ethos_verification_requests
drop policy if exists "Artists can view their own verification request" on public.ethos_verification_requests;
create policy "Artists can view their own verification request" on public.ethos_verification_requests
for select using (auth.uid() = user_id);
create policy "Admins can view all verification requests" on public.ethos_verification_requests
drop policy if exists "Admins can view all verification requests" on public.ethos_verification_requests;
create policy "Admins can view all verification requests" on public.ethos_verification_requests
for select using (
exists(
@ -54,9 +58,13 @@ create policy "Admins can view all verification requests" on public.ethos_verifi
)
);
create policy "Artists can submit verification request" on public.ethos_verification_requests
drop policy if exists "Artists can submit verification request" on public.ethos_verification_requests;
create policy "Artists can submit verification request" on public.ethos_verification_requests
for insert with check (auth.uid() = user_id);
create policy "Admins can update verification status" on public.ethos_verification_requests
drop policy if exists "Admins can update verification status" on public.ethos_verification_requests;
create policy "Admins can update verification status" on public.ethos_verification_requests
for update using (
exists(
@ -66,6 +74,8 @@ create policy "Admins can update verification status" on public.ethos_verificati
);
-- RLS Policies: ethos_verification_audit_log
create policy "Admins can view audit log" on public.ethos_verification_audit_log
drop policy if exists "Admins can view audit log" on public.ethos_verification_audit_log;
create policy "Admins can view audit log" on public.ethos_verification_audit_log
for select using (
exists(
@ -74,6 +84,8 @@ create policy "Admins can view audit log" on public.ethos_verification_audit_log
)
);
create policy "System can write audit logs" on public.ethos_verification_audit_log
drop policy if exists "System can write audit logs" on public.ethos_verification_audit_log;
create policy "System can write audit logs" on public.ethos_verification_audit_log
for insert with check (true);

View file

@ -44,9 +44,13 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_ethos_ecosystem_licenses_unique ON public.
ALTER TABLE public.ethos_ecosystem_licenses ENABLE ROW LEVEL SECURITY;
-- RLS Policies: ethos_ecosystem_licenses
CREATE POLICY "Artists can view their own ecosystem licenses" ON public.ethos_ecosystem_licenses
DROP POLICY IF EXISTS "Artists can view their own ecosystem licenses" ON public.ethos_ecosystem_licenses;
CREATE POLICY "Artists can view their own ecosystem licenses" ON public.ethos_ecosystem_licenses
FOR SELECT USING (auth.uid() = artist_id);
CREATE POLICY "Admins can view all ecosystem licenses" ON public.ethos_ecosystem_licenses
DROP POLICY IF EXISTS "Admins can view all ecosystem licenses" ON public.ethos_ecosystem_licenses;
CREATE POLICY "Admins can view all ecosystem licenses" ON public.ethos_ecosystem_licenses
FOR SELECT USING (
EXISTS(
@ -55,6 +59,8 @@ CREATE POLICY "Admins can view all ecosystem licenses" ON public.ethos_ecosystem
)
);
CREATE POLICY "Artists can create ecosystem license records" ON public.ethos_ecosystem_licenses
DROP POLICY IF EXISTS "Artists can create ecosystem license records" ON public.ethos_ecosystem_licenses;
CREATE POLICY "Artists can create ecosystem license records" ON public.ethos_ecosystem_licenses
FOR INSERT WITH CHECK (auth.uid() = artist_id);

View file

@ -211,13 +211,19 @@ alter table public.foundation_mentorship_sessions enable row level security;
alter table public.foundation_contributions enable row level security;
-- Courses: Published courses readable by all, all ops by instructor/admin
create policy "Published courses readable by all" on public.foundation_courses
drop policy if exists "Published courses readable by all" on public.foundation_courses;
create policy "Published courses readable by all" on public.foundation_courses
for select using (is_published = true or auth.uid() = instructor_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin'));
create policy "Instructors manage own courses" on public.foundation_courses
drop policy if exists "Instructors manage own courses" on public.foundation_courses;
create policy "Instructors manage own courses" on public.foundation_courses
for all using (auth.uid() = instructor_id) with check (auth.uid() = instructor_id);
-- Course modules: same as courses (published visible, instructor/admin manage)
create policy "Published modules readable by all" on public.foundation_course_modules
drop policy if exists "Published modules readable by all" on public.foundation_course_modules;
create policy "Published modules readable by all" on public.foundation_course_modules
for select using (
is_published = true or
@ -225,10 +231,14 @@ create policy "Published modules readable by all" on public.foundation_course_mo
exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin')
);
create policy "Instructors manage course modules" on public.foundation_course_modules
drop policy if exists "Instructors manage course modules" on public.foundation_course_modules;
create policy "Instructors manage course modules" on public.foundation_course_modules
for all using (exists(select 1 from public.foundation_courses where id = course_id and instructor_id = auth.uid()));
-- Lessons: same pattern
create policy "Published lessons readable by all" on public.foundation_course_lessons
drop policy if exists "Published lessons readable by all" on public.foundation_course_lessons;
create policy "Published lessons readable by all" on public.foundation_course_lessons
for select using (
is_published = true or
@ -236,69 +246,107 @@ create policy "Published lessons readable by all" on public.foundation_course_le
exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin')
);
create policy "Instructors manage course lessons" on public.foundation_course_lessons
drop policy if exists "Instructors manage course lessons" on public.foundation_course_lessons;
create policy "Instructors manage course lessons" on public.foundation_course_lessons
for all using (exists(select 1 from public.foundation_courses where id = course_id and instructor_id = auth.uid()));
-- Enrollments: users see own, instructors see their course enrollments
create policy "Users see own enrollments" on public.foundation_enrollments
drop policy if exists "Users see own enrollments" on public.foundation_enrollments;
create policy "Users see own enrollments" on public.foundation_enrollments
for select using (auth.uid() = user_id or
exists(select 1 from public.foundation_courses where id = course_id and instructor_id = auth.uid()));
create policy "Users manage own enrollments" on public.foundation_enrollments
drop policy if exists "Users manage own enrollments" on public.foundation_enrollments;
create policy "Users manage own enrollments" on public.foundation_enrollments
for insert with check (auth.uid() = user_id);
create policy "Users update own enrollments" on public.foundation_enrollments
drop policy if exists "Users update own enrollments" on public.foundation_enrollments;
create policy "Users update own enrollments" on public.foundation_enrollments
for update using (auth.uid() = user_id);
-- Lesson progress: users see own
create policy "Users see own lesson progress" on public.foundation_lesson_progress
drop policy if exists "Users see own lesson progress" on public.foundation_lesson_progress;
create policy "Users see own lesson progress" on public.foundation_lesson_progress
for select using (auth.uid() = user_id);
create policy "Users update own lesson progress" on public.foundation_lesson_progress
drop policy if exists "Users update own lesson progress" on public.foundation_lesson_progress;
create policy "Users update own lesson progress" on public.foundation_lesson_progress
for insert with check (auth.uid() = user_id);
create policy "Users update own lesson completion" on public.foundation_lesson_progress
drop policy if exists "Users update own lesson completion" on public.foundation_lesson_progress;
create policy "Users update own lesson completion" on public.foundation_lesson_progress
for update using (auth.uid() = user_id);
-- Achievements: all readable, admin/system manages
create policy "Achievements readable by all" on public.foundation_achievements
drop policy if exists "Achievements readable by all" on public.foundation_achievements;
create policy "Achievements readable by all" on public.foundation_achievements
for select using (true);
-- User achievements: users see own, admin manages
create policy "Users see own achievements" on public.foundation_user_achievements
drop policy if exists "Users see own achievements" on public.foundation_user_achievements;
create policy "Users see own achievements" on public.foundation_user_achievements
for select using (auth.uid() = user_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin'));
-- Mentors: approved mentors visible, mentors manage own
create policy "Approved mentors visible to all" on public.foundation_mentors
drop policy if exists "Approved mentors visible to all" on public.foundation_mentors;
create policy "Approved mentors visible to all" on public.foundation_mentors
for select using (approval_status = 'approved' or auth.uid() = user_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin'));
create policy "Users manage own mentor profile" on public.foundation_mentors
drop policy if exists "Users manage own mentor profile" on public.foundation_mentors;
create policy "Users manage own mentor profile" on public.foundation_mentors
for all using (auth.uid() = user_id) with check (auth.uid() = user_id);
-- Mentorship requests: involved parties can see
create policy "Mentorship requests visible to involved" on public.foundation_mentorship_requests
drop policy if exists "Mentorship requests visible to involved" on public.foundation_mentorship_requests;
create policy "Mentorship requests visible to involved" on public.foundation_mentorship_requests
for select using (auth.uid() = mentor_id or auth.uid() = mentee_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin'));
create policy "Mentees request mentorship" on public.foundation_mentorship_requests
drop policy if exists "Mentees request mentorship" on public.foundation_mentorship_requests;
create policy "Mentees request mentorship" on public.foundation_mentorship_requests
for insert with check (auth.uid() = mentee_id);
create policy "Mentors respond to requests" on public.foundation_mentorship_requests
drop policy if exists "Mentors respond to requests" on public.foundation_mentorship_requests;
create policy "Mentors respond to requests" on public.foundation_mentorship_requests
for update using (auth.uid() = mentor_id);
-- Mentorship sessions: involved parties can see/manage
create policy "Sessions visible to involved" on public.foundation_mentorship_sessions
drop policy if exists "Sessions visible to involved" on public.foundation_mentorship_sessions;
create policy "Sessions visible to involved" on public.foundation_mentorship_sessions
for select using (auth.uid() = mentor_id or auth.uid() = mentee_id);
create policy "Mentorship sessions insert" on public.foundation_mentorship_sessions
drop policy if exists "Mentorship sessions insert" on public.foundation_mentorship_sessions;
create policy "Mentorship sessions insert" on public.foundation_mentorship_sessions
for insert with check (auth.uid() = mentor_id or auth.uid() = mentee_id);
create policy "Mentorship sessions update" on public.foundation_mentorship_sessions
drop policy if exists "Mentorship sessions update" on public.foundation_mentorship_sessions;
create policy "Mentorship sessions update" on public.foundation_mentorship_sessions
for update using (auth.uid() = mentor_id or auth.uid() = mentee_id);
-- Contributions: users see own, admin sees all
create policy "Contributions visible to user and admin" on public.foundation_contributions
drop policy if exists "Contributions visible to user and admin" on public.foundation_contributions;
create policy "Contributions visible to user and admin" on public.foundation_contributions
for select using (auth.uid() = user_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin'));
create policy "System logs contributions" on public.foundation_contributions
drop policy if exists "System logs contributions" on public.foundation_contributions;
create policy "System logs contributions" on public.foundation_contributions
for insert with check (true);

View file

@ -6,14 +6,14 @@ alter table if exists storage.objects enable row level security;
-- Allow public read for objects in post_media bucket (because bucket is public)
DO $$ BEGIN
CREATE POLICY IF NOT EXISTS post_media_public_read ON storage.objects
CREATE POLICY post_media_public_read ON storage.objects
FOR SELECT TO public
USING (bucket_id = 'post_media');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
-- Allow authenticated users to upload to post_media bucket
DO $$ BEGIN
CREATE POLICY IF NOT EXISTS post_media_auth_insert ON storage.objects
CREATE POLICY post_media_auth_insert ON storage.objects
FOR INSERT TO authenticated
WITH CHECK (bucket_id = 'post_media');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;

View file

@ -158,15 +158,15 @@ ALTER TABLE api_keys ENABLE ROW LEVEL SECURITY;
ALTER TABLE api_usage_logs ENABLE ROW LEVEL SECURITY;
ALTER TABLE developer_profiles ENABLE ROW LEVEL SECURITY;
-- Users can only see their own API keys
DROP POLICY IF EXISTS api_keys_user_policy ON api_keys;
CREATE POLICY api_keys_user_policy ON api_keys
FOR ALL USING (auth.uid() = user_id);
-- Users can only see their own usage logs
DROP POLICY IF EXISTS api_usage_logs_user_policy ON api_usage_logs;
CREATE POLICY api_usage_logs_user_policy ON api_usage_logs
FOR ALL USING (auth.uid() = user_id);
-- Users can only see their own developer profile
DROP POLICY IF EXISTS developer_profiles_user_policy ON developer_profiles;
CREATE POLICY developer_profiles_user_policy ON developer_profiles
FOR ALL USING (auth.uid() = user_id);

View file

@ -0,0 +1,7 @@
-- Update OAuth client redirect URIs to include localhost:8080 for local dev
-- This enables Foundation login to work in both production and development
UPDATE public.oauth_clients
SET redirect_uris = '["https://aethex.dev/auth/callback", "http://localhost:8080/auth/callback", "http://localhost:3000/auth/callback", "http://localhost:5173/auth/callback"]'::jsonb,
updated_at = NOW()
WHERE client_id = 'aethex_corp';