396ebf9837
Deploy / deploy (push) Successful in 3m45s
The deploy workflow pulled, built and started the app, but never applied migrations. Shipping a change that adds a table therefore broke the app until someone remembered to migrate by hand -- the new api_keys table would have done exactly that to the settings page. The workflow now builds, applies pending migrations, and only then starts the app. A failed migration exits non-zero, so the deploy fails instead of starting an app whose schema is behind its code. Because `up -d` is never reached in that case, production keeps serving the previous containers. Migrations run through a new `migrate` compose service built from the Dockerfile's builder stage, rather than `docker compose exec app npx prisma migrate deploy` as the README previously suggested. The production image copies prisma/ and node_modules/.prisma but not the Prisma CLI, which is a devDependency and is absent from the standalone bundle, so that command would have had npx download Prisma inside the container at runtime as the unprivileged nextjs user. The builder stage has the CLI and its engines already. The service sits behind a `tools` profile so `docker compose up` never starts it, and takes DATABASE_URL from compose rather than a .env file -- dotenv does not override variables that are already set, so the compose value wins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
206 lines
5.4 KiB
Markdown
206 lines
5.4 KiB
Markdown
# 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](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 |
|
|
| PDF | HTML render via `/api/pdf/[id]` |
|
|
|
|
---
|
|
|
|
## Prerequisites
|
|
|
|
- Node.js 20+
|
|
- PostgreSQL 16 (or Docker)
|
|
- npm 10+
|
|
- `ts-node` for seeding: `npm install -g ts-node typescript`
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### 1. Clone & install
|
|
|
|
```bash
|
|
git clone <repo-url>
|
|
cd xBid
|
|
npm install
|
|
```
|
|
|
|
### 2. Configure environment
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
Edit `.env`:
|
|
|
|
```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):**
|
|
|
|
```bash
|
|
docker compose up -d postgres
|
|
```
|
|
|
|
**Option B — local PostgreSQL:**
|
|
|
|
```sql
|
|
CREATE DATABASE xbid;
|
|
```
|
|
|
|
### 4. Run database migrations
|
|
|
|
```bash
|
|
npm run db:generate # generate Prisma client
|
|
npm run db:migrate # run migrations (enter "init" as migration name)
|
|
```
|
|
|
|
### 5. Seed sample data
|
|
|
|
```bash
|
|
npm run db:seed
|
|
```
|
|
|
|
This creates 15 rate cards, 2 sample clients, 2 jobs with shots, assets, and line items.
|
|
|
|
### 6. Start development server
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
Open http://localhost:3000
|
|
|
|
---
|
|
|
|
## Production (Docker)
|
|
|
|
```bash
|
|
docker compose up --build -d
|
|
```
|
|
|
|
Pushing to `main` triggers the Gitea workflow in `.gitea/workflows/deploy.yml`,
|
|
which pulls, builds, **applies pending migrations, and only then starts the app**.
|
|
A failed migration fails the deploy rather than starting an app whose schema is
|
|
behind its code, so there is no manual migration step.
|
|
|
|
Migrations run through the `migrate` service, which builds from the Dockerfile
|
|
`builder` stage. That matters: the production image ships runtime dependencies
|
|
only, and the Prisma CLI is a devDependency, so `docker compose exec app npx
|
|
prisma ...` would try to download Prisma inside the container at runtime.
|
|
|
|
To run migrations by hand (or to seed on a first deploy):
|
|
|
|
```bash
|
|
docker compose --profile tools run --rm migrate
|
|
docker compose --profile tools run --rm migrate 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):
|
|
|
|
```bash
|
|
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](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
|
|
|
|
```bash
|
|
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)
|
|
```
|