Fiscal Clone 3.0
Turbopack-first rebuild of a fiscal.ai-style terminal with OpenClaw integration.
Stack
- Next.js 16 App Router
- Turbopack for
devandbuild - Better Auth (email/password, magic link, admin, organization plugins)
- PostgreSQL adapter for Better Auth
- Internal API routes (
app/api/*) - Durable local task engine and JSON data store
- OpenClaw/ZeroClaw analysis via OpenAI-compatible chat endpoint
Run locally
npm install
npm run dev
Open http://localhost:3000.
Better Auth requires PostgreSQL. Set DATABASE_URL, BETTER_AUTH_SECRET, and BETTER_AUTH_BASE_URL in .env.local.
Auth tables are migrated automatically on first authenticated request.
Production build
npm run build
npm 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 local override also starts PostgreSQL and wires DATABASE_URL to postgres://postgres:postgres@postgres:5432/fiscal_clone.
For Coolify/remote Docker Compose, only container port 3000 is exposed internally (no fixed host port bind), avoiding host port collisions.
Runtime data persists in the app_data volume (/app/data in container).
Docker builds install the npm version from NPM_VERSION (default latest).
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
BETTER_AUTH_SECRET=replace-with-a-long-random-secret
BETTER_AUTH_BASE_URL=http://localhost:3000
BETTER_AUTH_ADMIN_USER_IDS=
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>
If OpenClaw is unset, the app uses local fallback analysis so task workflows still run.
API surface
GET|POST|PATCH|PUT|DELETE /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