Platform Apps
Learn about and work with all 7 platform applications that make up the OneApp ecosystem — including the main consumer app, API server, admin panel, documentation site, component library, mobile app, and email templates.
Know which app you need?
Why platform apps matter
Managing multiple applications without proper organization creates problems:
- Duplicate infrastructure — Every app rebuilds authentication, database access, UI components from scratch
- Version drift — Apps use different versions of React, Next.js, causing deployment conflicts
- No code sharing — Same features implemented differently across web, mobile, admin
- Configuration chaos — Each app has different ESLint rules, TypeScript configs, env vars
- Deployment confusion — No clear understanding of which app runs where on what port
- Team friction — Frontend team doesn't know which app to work on for specific features
OneApp's platform architecture uses a unified monorepo with shared packages (@repo/*) — all apps share
authentication (@repo/auth), database client (@repo/db-prisma), UI components (@repo/uni-ui), and AI integration
(@repo/ai) — ensuring consistency across web, mobile, and admin experiences.
Production-ready with 7 battle-tested applications (handling production traffic daily), microfrontend architecture for code splitting, shared environment configuration, unified deployment pipeline, automatic dependency updates, and instant hot-reload during development.
Use cases
Master platform apps to:
- Build features faster — Share authentication, database, UI across all apps
- Develop locally — Run full stack with one command (
pnpm dev:oneapp) - Scale independently — Deploy web app separately from API server
- Maintain consistency — All apps use same design system, auth flow, error handling
- Test components — Preview UI in Storybook before using in production
- Ship to mobile — Use same components in React Native via
@repo/uni-ui
Quick Start
Run the full stack
# Start main app with microfrontends (recommended)
pnpm dev:oneapp
# This starts:
# - oneapp-onstage (port 3500) - Main consumer app
# - oneapp-backstage (port 3600) - Admin panel (microfrontend)
# - oneapp-api (port 3001) - REST API serverOpen in browser:
- Main app: http://localhost:3500
- Admin panel: http://localhost:3500/backstage (microfrontend)
- API server: http://localhost:3001/api/health
That's it! The full stack is running with live reload.
Run individual apps
# Documentation site
pnpm --filter=docs dev # Port 3000
# Component showcase
pnpm --filter=storybook dev # Port 6006
# Mobile app (Expo)
pnpm --filter=mobile-app dev # Opens Expo DevTools
# Email templates
pnpm --filter=email dev # Port 3004App architecture overview
The platform follows a microfrontend architecture where the main app (onstage) hosts smaller apps (backstage) as embedded modules:
┌─────────────────────────────────────────────────────────────┐
│ oneapp-onstage (3500) │
│ Main Consumer Application │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Chat & AI │ │ Documents │ │ Presentations│ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ oneapp-backstage (Microfrontend) │ │
│ │ /backstage route - Admin Panel │ │
│ └────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────┐
│ oneapp-api (3001) │
│ REST API Server │
│ GET/POST/PUT/DELETE /api/* │
└──────────────────────────────┘
│
▼
┌──────────────────────────────┐
│ Neon Postgres Database │
│ + Upstash Redis Cache │
│ + Upstash Vector (RAG) │
└──────────────────────────────┘Data flow:
- User → Interacts with onstage UI
- onstage → Calls oneapp-api for data
- oneapp-api → Queries Postgres/Redis/Vector DB
- Response → Returns to onstage → Displays to user
Complete app reference
All 7 platform applications
Consumer Applications
| App | Port | Framework | Purpose | Documentation |
|---|---|---|---|---|
| oneapp-onstage | 3500 | Next.js 16 | Main consumer application with chat, documents, presentations | View docs → |
| mobile-app | - | Expo 52 + Next.js 16 | iOS/Android app with offline-first architecture | View docs → |
Use when: Building user-facing features, chat interfaces, document editing
Backend & APIs
| App | Port | Framework | Purpose | Documentation |
|---|---|---|---|---|
| oneapp-api | 3001 | Next.js 16 | Dynamic CRUD REST API with auto-generated endpoints | View docs → |
Use when: Building API endpoints, server-side logic, database operations
Admin & Configuration
| App | Port | Framework | Purpose | Documentation |
|---|---|---|---|---|
| oneapp-backstage | 3600 | Next.js 16 | AI workflow designer, admin panel, user management | View docs → |
Use when: Managing workflows, administering users, configuring AI agents
Developer Tools
| App | Port | Framework | Purpose | Documentation |
|---|---|---|---|---|
| docs | 3000 | Docusaurus 3 | Project documentation with versioning | View docs → |
| storybook | 6006 | Storybook 8 | Component library showcase and testing | View docs → |
| 3004 | React Email | Email template preview and development | View docs → |
Use when: Writing documentation, developing components, previewing emails
Shared dependencies
All platform apps share core packages for consistency:
| Package | Used By | Purpose |
|---|---|---|
@repo/auth | onstage, backstage, mobile | Better Auth authentication |
@repo/db-prisma | onstage, api, backstage | Prisma 7 database client |
@repo/ai | onstage, backstage, mobile | Vercel AI SDK v6 wrapper |
@repo/ui | onstage, backstage | React 19 web components |
@repo/uni-ui | onstage, mobile, docs | Universal web + native components |
@repo/email | onstage, api, email | React Email templates |
@repo/analytics | onstage, mobile, docs | PostHog analytics |
@repo/observability | onstage, api, backstage | Sentry error tracking |
Benefits:
- ✅ Single version of React, Next.js, TypeScript across all apps
- ✅ Update a component once, all apps get the change
- ✅ Shared authentication state between web and mobile
- ✅ Consistent error handling, logging, analytics
Development workflow
Full stack development
# Terminal 1: Start full stack
pnpm dev:oneapp
# Terminal 2: Watch for package changes
pnpm --filter=@repo/uni-ui dev
# Terminal 3: Run tests
pnpm --filter=oneapp-onstage test --watchComponent development
# Terminal 1: Storybook for component preview
pnpm --filter=storybook dev
# Terminal 2: Main app to test integration
pnpm --filter=oneapp-onstage devMobile development
# Terminal 1: Mobile app
pnpm --filter=mobile-app dev
# Terminal 2: API server (for data)
pnpm --filter=oneapp-api dev
# Scan QR code with Expo Go app to test on deviceNext steps
- Explore shared packages: Shared Packages →
- Learn workspace architecture: Workspace Architecture →
- Master dependency management: Dependency Management →
For Developers: Environment configuration, deployment, and troubleshooting
Environment configuration
Shared environment variables
All apps share common environment variables for consistency:
Database (All Apps)
# Neon Postgres
DATABASE_URL="postgresql://user:password@host.neon.tech/db?sslmode=require"
DATABASE_URL_UNPOOLED="postgresql://user:password@host.neon.tech/db?sslmode=require"
# Upstash Redis
UPSTASH_REDIS_REST_URL="https://your-redis.upstash.io"
UPSTASH_REDIS_REST_TOKEN="your-token"
# Upstash Vector
UPSTASH_VECTOR_REST_URL="https://your-vector.upstash.io"
UPSTASH_VECTOR_REST_TOKEN="your-token"Authentication (onstage, backstage, mobile)
# Better Auth
BETTER_AUTH_SECRET="your-secret-key"
BETTER_AUTH_URL="http://localhost:3500"
TRUSTED_ORIGINS="http://localhost:3500,http://localhost:3600"
# OAuth Providers
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"
GITHUB_CLIENT_ID="your-github-client-id"
GITHUB_CLIENT_SECRET="your-github-client-secret"Important: Keep BETTER_AUTH_SECRET consistent across all apps for session sharing.
AI Services (onstage, backstage, mobile)
# Cloudflare AI Gateway
AI_GATEWAY_API_KEY="your-gateway-key"
AI_GATEWAY_URL="https://gateway.ai.cloudflare.com/v1/account/gateway/ai"
# LLM Providers
OPENAI_API_KEY="sk-..."
ANTHROPIC_API_KEY="sk-ant-..."
GROQ_API_KEY="gsk_..."Observability (All Production Apps)
# Sentry
SENTRY_DSN="https://...@sentry.io/..."
SENTRY_AUTH_TOKEN="your-auth-token"
# BetterStack
BETTERSTACK_SOURCE_TOKEN="your-source-token"
# PostHog
NEXT_PUBLIC_POSTHOG_KEY="phc_..."
NEXT_PUBLIC_POSTHOG_HOST="https://app.posthog.com"App-specific environment variables
oneapp-onstage
# App-specific
NEXT_PUBLIC_APP_URL="http://localhost:3500"
NEXT_PUBLIC_API_URL="http://localhost:3001"
NEXT_PUBLIC_BACKSTAGE_URL="http://localhost:3600"
# Feature flags
NEXT_PUBLIC_ENABLE_AI_CHAT="true"
NEXT_PUBLIC_ENABLE_DOCUMENTS="true"
NEXT_PUBLIC_ENABLE_PRESENTATIONS="true"oneapp-api
# API Configuration
API_PORT="3001"
API_RATE_LIMIT="100"
API_TIMEOUT="30000"
# CORS
ALLOWED_ORIGINS="http://localhost:3500,http://localhost:3600"mobile-app
# Expo
EXPO_PUBLIC_API_URL="http://localhost:3001"
EXPO_PUBLIC_AUTH_URL="http://localhost:3500"
# EAS Build
EAS_PROJECT_ID="your-project-id"Deployment guide
Vercel (onstage, api, backstage)
{
"buildCommand": "pnpm build",
"devCommand": "pnpm dev",
"installCommand": "pnpm install",
"framework": "nextjs",
"outputDirectory": ".next"
}Deploy:
# Install Vercel CLI
pnpm install -g vercel
# Link project
vercel link
# Deploy to preview
vercel
# Deploy to production
vercel --prodEnvironment variables:
- Set in Vercel Dashboard → Settings → Environment Variables
- Separate values for Development, Preview, Production
Cloudflare Pages (docs)
name = "forge-docs"
compatibility_date = "2025-01-01"
[build]
command = "pnpm build"
output_directory = "build"
[[pages_plugins]]
binding = "ASSETS"Deploy:
# Install Wrangler CLI
pnpm install -g wrangler
# Login
wrangler login
# Deploy
wrangler pages deploy buildChromatic (Storybook)
# Install Chromatic CLI
pnpm add -D chromatic
# Deploy to Chromatic
pnpm --filter=storybook chromatic --project-token=<token>Benefits:
- ✅ Visual regression testing
- ✅ Component change detection
- ✅ Automated screenshot comparisons
EAS Build (mobile-app)
export default {
expo: {
name: "OneApp Mobile",
slug: "forge-mobile",
version: "1.0.0",
ios: {
bundleIdentifier: "com.forge.mobile"
},
android: {
package: "com.forge.mobile"
}
}
};Build and submit:
# Install EAS CLI
pnpm install -g eas-cli
# Login
eas login
# Build iOS
eas build --platform ios
# Build Android
eas build --platform android
# Submit to App Store
eas submit --platform ios
# Submit to Play Store
eas submit --platform androidPort reference
Quick reference for all app ports:
| Port | App | URL |
|---|---|---|
| 3000 | docs | http://localhost:3000 |
| 3001 | oneapp-api | http://localhost:3001 |
| 3004 | http://localhost:3004 | |
| 3500 | oneapp-onstage | http://localhost:3500 |
| 3600 | oneapp-backstage | http://localhost:3600 |
| 6006 | storybook | http://localhost:6006 |
| 8081 | mobile-app (Expo) | exp://localhost:8081 |
Port conflicts:
# Kill process on port 3500
lsof -ti:3500 | xargs kill -9
# Or use different port
pnpm --filter=oneapp-onstage dev -- -p 3501Troubleshooting
App won't start
# Clean install
pnpm clean && pnpm install
# Rebuild dependencies
pnpm build
# Check port availability
lsof -ti:3500Environment variables not loading
# Verify .env.local exists
ls -la platform/apps/oneapp-onstage/.env.local
# Check env validation
pnpm --filter=oneapp-onstage typecheck
# Restart dev server
# Cmd/Ctrl+C → pnpm devMicrofrontend not loading
# Verify backstage is running
curl http://localhost:3600
# Check CORS configuration
# oneapp-api/.env.local:
# ALLOWED_ORIGINS="http://localhost:3500,http://localhost:3600"
# Restart both apps
pnpm dev:oneappDatabase connection fails
# Test connection
pnpm --filter=oneapp-api prisma db push
# Verify environment variables
echo $DATABASE_URL
# Check Neon dashboard
# https://console.neon.tech/Mobile app not connecting to API
# Use local IP instead of localhost
# mobile-app/.env.local:
# EXPO_PUBLIC_API_URL="http://192.168.1.100:3001"
# Find your local IP
ipconfig getifaddr en0 # macOS
ip addr show # Linux
ipconfig # Windows
# Allow API CORS for mobile
# oneapp-api/.env.local:
# ALLOWED_ORIGINS="http://192.168.1.100:3500"Build fails in CI
# Ensure frozen lockfile
pnpm install --frozen-lockfile
# Build in correct order
pnpm --filter=@repo/types build
pnpm --filter=@repo/utils build
pnpm --filter=oneapp-onstage build
# Or use dependencies
pnpm --filter=oneapp-onstage... buildAdvanced patterns
Microfrontend architecture
Host app (oneapp-onstage):
export default {
async rewrites() {
return [
{
source: "/backstage/:path*",
destination: process.env.BACKSTAGE_URL + "/:path*"
}
];
}
};Remote app (oneapp-backstage):
export default {
basePath: "/backstage",
assetPrefix: process.env.NODE_ENV === "production" ? "https://backstage.example.com" : ""
};Shared authentication
All apps use the same auth instance:
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { prisma } from "@repo/db-prisma";
export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: "postgresql"
}),
emailAndPassword: {
enabled: true
},
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!
}
}
});Usage in apps:
import { auth } from "@repo/auth/server";
import { headers } from "next/headers";
export default async function Page() {
const session = await auth.api.getSession({
headers: await headers()
});
return <h1>Welcome, {session?.user.name}</h1>;
}Shared database client
All apps use the same Prisma instance:
import { PrismaClient } from "@prisma/client";
const globalForPrisma = globalThis as unknown as {
prisma: PrismaClient | undefined;
};
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== "production") {
globalForPrisma.prisma = prisma;
}Usage:
import { prisma } from "@repo/db-prisma";
export async function GET() {
const users = await prisma.user.findMany();
return Response.json(users);
}CI/CD Pipeline
GitHub Actions workflow
name: CI
on:
push:
branches: [main, develop]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 22
cache: "pnpm"
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: pnpm lint
- run: pnpm typecheck
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Vercel
run: vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}Performance optimization
Build caching with Turborepo
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"],
"cache": true
},
"dev": {
"cache": false,
"persistent": true
}
}
}Selective builds
# Build only changed apps
pnpm --filter="[origin/main]" build
# Build app and dependencies
pnpm --filter=oneapp-onstage... build
# Build app and dependents
pnpm --filter=...@repo/uni-ui build