3.3 KiB
Fiscal Clone 3.0
Turbopack-first rebuild of a fiscal.ai-style terminal with OpenClaw integration.
Stack
- Next.js 16 App Router
- Bun runtime/tooling
- Elysia route layer mounted in Next Route Handlers
- Turbopack for
devandbuild - Better Auth (email/password + magic link)
- Drizzle ORM (PostgreSQL) + Better Auth Drizzle adapter
- Internal API routes via Elysia app module (
lib/server/api/app.ts) - Eden Treaty for type-safe frontend API calls
- Workflow DevKit + Postgres World for durable background task execution
- PostgreSQL-backed domain storage (watchlist, holdings, filings, tasks, insights)
- OpenClaw/ZeroClaw analysis via OpenAI-compatible chat endpoint
Run locally
bun install
bun run dev
Open http://localhost:3000.
Better Auth requires PostgreSQL. Set DATABASE_URL, BETTER_AUTH_SECRET, and BETTER_AUTH_BASE_URL in .env.local.
Generate/apply schema migrations and set up the workflow world tables before starting the app:
bun run db:generate
bun run db:migrate
bun run workflow:setup
Production build
bun run db:migrate
bun run build
bun run start
Docker deployment
cp .env.example .env
docker compose up --build -d
For local Docker, host port mapping comes from docker-compose.override.yml (default http://localhost:3000, configurable via APP_PORT).
The base Docker Compose now includes an internal PostgreSQL service (postgres) used by Better Auth by default.
On container startup, the app now applies Drizzle migrations automatically before launching Next.js.
For Coolify/remote Docker Compose, only app container port 3000 is exposed internally (no fixed host port bind), avoiding host port collisions.
If you use an external Postgres instance, set DATABASE_URL explicitly.
Docker images use Bun (oven/bun:1.3.5-alpine) for build and runtime.
Environment
Use root .env or root .env.local:
# leave blank for same-origin API
NEXT_PUBLIC_API_URL=
DATABASE_URL=postgres://postgres:postgres@localhost:5432/fiscal_clone
POSTGRES_DB=fiscal_clone
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
BETTER_AUTH_SECRET=replace-with-a-long-random-secret
BETTER_AUTH_BASE_URL=http://localhost:3000
BETTER_AUTH_TRUSTED_ORIGINS=http://localhost:3000
OPENCLAW_BASE_URL=http://localhost:4000
OPENCLAW_API_KEY=your_key
OPENCLAW_MODEL=zeroclaw
SEC_USER_AGENT=Fiscal Clone <support@fiscal.local>
WORKFLOW_TARGET_WORLD=@workflow/world-postgres
WORKFLOW_POSTGRES_URL=postgres://postgres:postgres@localhost:5432/fiscal_clone
WORKFLOW_POSTGRES_JOB_PREFIX=fiscal_clone
WORKFLOW_POSTGRES_WORKER_CONCURRENCY=10
If OpenClaw is unset, the app uses local fallback analysis so task workflows still run.
API surface
All endpoints below are defined in Elysia at lib/server/api/app.ts and exposed via app/api/[[...slugs]]/route.ts.
ALL /api/auth/*(Better Auth handler)GET /api/healthGET /api/meGET|POST /api/watchlistDELETE /api/watchlist/:idGET|POST /api/portfolio/holdingsPATCH|DELETE /api/portfolio/holdings/:idGET /api/portfolio/summaryPOST /api/portfolio/refresh-pricesPOST /api/portfolio/insights/generateGET /api/portfolio/insights/latestGET /api/filingsPOST /api/filings/syncPOST /api/filings/:accessionNumber/analyzeGET /api/tasksGET /api/tasks/:taskId