# 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 `dev` and `build` - 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 ```bash bun install bun run dev ``` Open [http://localhost:3000](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: ```bash bun run db:generate bun run db:migrate bun run workflow:setup ``` ## Production build ```bash bun run db:migrate bun run build bun run start ``` ## Docker deployment ```bash 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`: ```env # 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 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/health` - `GET /api/me` - `GET|POST /api/watchlist` - `DELETE /api/watchlist/:id` - `GET|POST /api/portfolio/holdings` - `PATCH|DELETE /api/portfolio/holdings/:id` - `GET /api/portfolio/summary` - `POST /api/portfolio/refresh-prices` - `POST /api/portfolio/insights/generate` - `GET /api/portfolio/insights/latest` - `GET /api/filings` - `POST /api/filings/sync` - `POST /api/filings/:accessionNumber/analyze` - `GET /api/tasks` - `GET /api/tasks/:taskId`