Adds a key-authenticated REST API at /api/v1 so another system can create and manage quotes without going through the UI. Endpoints cover quotes (list, create, read, update, delete, recalculate), shots, assets and line items, plus read-only clients and rate cards. POST /api/v1/quotes builds a whole priced quote -- client, shots, assets and tasks -- in a single transaction. Routes are also mounted under /api/v1/jobs, since a quote and a job are the same record here. Keys are stored as SHA-256 with a display prefix, so the plaintext is shown once at creation and is not recoverable. They carry read/write scopes, can be revoked (effective on the next request), and record when they were last used. Minting and revoking live in Settings and are restricted to signed-in admins. /api/v1 is exempt from the session proxy because it authenticates with a bearer key rather than a cookie -- without this, every API call was redirected to /login as a 307. It is not unprotected: each route handler requires a live, unrevoked key with the right scope. Shot numbering and shot-code construction move into lib/shot-codes.ts so the UI and the API cannot drift. This also fixes numbering restarting at 0010 when a scene was entered in a different case to the stored one: the lookup upper-cased the scene but the stored value was left as typed. Unspecified currency and markup/tax/discount on an API-created quote fall back to the studio's configured quote defaults. Decimal fields are serialised as strings to preserve the exact precision the app's decimal arithmetic maintains. Note: this needs `prisma migrate deploy` for the new api_keys table. Settings will error for admins until that runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4.7 KiB
xBid — VFX Quoting & Bidding SaaS
A professional full-stack VFX quoting application built with Next.js 15, TypeScript, Tailwind CSS v4, Prisma ORM, and PostgreSQL.
Features
- Clients — manage client companies with full contact and billing info
- Jobs / Quotes — versioned quote documents with status workflow (Draft ? Sent ? Approved/Rejected)
- Shots — VFX shot breakdown with complexity multipliers and drag-and-drop reordering
- Assets — CG asset budget tracking (characters, environments, vehicles, etc.)
- Line Items — per-task cost rows with hours/days/artists/rates, markup, discount, tax
- Rate Cards — studio rate card library organized by department
- PDF Export — professional quote PDF with front page + detailed appendix
- Decimal Precision — all financials use
decimal.js(no floating-point drift) - REST API - create and manage quotes, shots, assets and tasks programmatically (API.md)
Tech Stack
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router, Server Actions) |
| Language | TypeScript |
| Styling | Tailwind CSS v4 + shadcn/ui |
| ORM | Prisma 7 + PostgreSQL 16 |
| Forms | React Hook Form + Zod |
| Drag & Drop | @dnd-kit/core + @dnd-kit/sortable |
| Finance Math | decimal.js |
| Notifications | sonner |
HTML render via /api/pdf/[id] |
Prerequisites
- Node.js 20+
- PostgreSQL 16 (or Docker)
- npm 10+
ts-nodefor seeding:npm install -g ts-node typescript
Quick Start
1. Clone & install
git clone <repo-url>
cd xBid
npm install
2. Configure environment
cp .env.example .env
Edit .env:
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/xbid"
NEXTAUTH_SECRET="your-random-secret-here"
NEXTAUTH_URL="http://localhost:3000"
3. Start PostgreSQL
Option A — Docker (recommended):
docker compose up -d postgres
Option B — local PostgreSQL:
CREATE DATABASE xbid;
4. Run database migrations
npm run db:generate # generate Prisma client
npm run db:migrate # run migrations (enter "init" as migration name)
5. Seed sample data
npm run db:seed
This creates 15 rate cards, 2 sample clients, 2 jobs with shots, assets, and line items.
6. Start development server
npm run dev
Production (Docker)
docker compose up --build -d
After first run, apply migrations:
docker compose exec app npx prisma migrate deploy
docker compose exec app npx prisma db seed
PDF Export
Navigate to any job and click Download PDF. The route at /api/pdf/[id] generates HTML with:
- Front page: client info, project details, shot/asset summary, financial totals, T&C
- Appendix: full per-shot and per-asset line item breakdown
Print to PDF via browser (Ctrl+P ? Save as PDF).
REST API
xBid exposes a REST API at /api/v1 so another system can create and manage
quotes, shots, assets and tasks without anyone opening the UI.
Requests authenticate with an API key, created under Settings -> API Keys (admins only):
curl -s http://localhost:3000/api/v1 \
-H "Authorization: Bearer $XBID_API_KEY"
That endpoint lists every available route and confirms what the key may do. See API.md for the full reference: endpoints, pricing rules, shot code generation and error codes.
Note: GET_SHOTS.md documents the opposite direction - the review app's API
that xBid pulls shots from.
Project Structure
src/
app/ Next.js App Router pages
api/pdf/[id]/ PDF generation endpoint
clients/ Client management
jobs/ Job management
rate-cards/ Rate card management
actions/ Server actions (CRUD)
components/
assets/ Asset editor
clients/ Client form & table
dashboard/ Stats & recent jobs
jobs/ Job form, table, detail, totals
layout/ Sidebar navigation
line-items/ Line item table & dialog
rate-cards/ Rate card management
shots/ Shot editor
ui/ shadcn/ui components
lib/
calculations.ts Decimal.js financial math
constants.ts Domain constants & defaults
prisma.ts Prisma client singleton
validations.ts Zod schemas
prisma/
schema.prisma Full database schema
seed.ts Sample data seeder
Database Scripts
npm run db:generate # npx prisma generate
npm run db:migrate # npx prisma migrate dev
npm run db:seed # ts-node prisma/seed.ts
npm run db:studio # npx prisma studio (DB GUI at :5555)