Built by Jenna de Beer.
A safe, self-contained backend API demo that models a generic operations workflow — customers raise jobs, parts are pulled from inventory, quotes are issued and approved, invoices are sent and paid, and every meaningful change leaves an audit trail.
Built with Node.js, TypeScript, Express, Prisma, Zod, and Vitest. SQLite is used for the local demo; the schema is written with PostgreSQL-style relational modelling in mind. No frontend, no real-world data, no production secrets — this repo is a focused demonstration of backend API and database thinking.
Operations teams running real-world workflows — service jobs, parts inventory, quoting and invoicing — need a backend that enforces business rules:
- Jobs only move through valid statuses.
- Stock never goes negative.
- Quotes drive job progress.
- Every meaningful change leaves an audit trail.
This repo models that backend in a clean, focused way so the data and workflow thinking can be reviewed without any of the noise of a full production system.
- REST API design with predictable resource routes
- TypeScript backend architecture (routes / services / validators / middleware)
- Relational data modelling with Prisma
- Business workflow logic with explicit state machines (jobs, quotes, invoices)
- Inventory stock adjustments with a hard non-negative constraint
- Validation at the edge with Zod
- Transactional audit logging — every important action writes a log row inside the same database transaction as the change it describes
- Tests using Vitest + Supertest against a real database
- Continuous integration with GitHub Actions (Node 20 + 22 matrix)
| Layer | Choice |
|---|---|
| Runtime | Node.js 20+ |
| Language | TypeScript |
| HTTP framework | Express 5 |
| ORM | Prisma |
| Validation | Zod |
| Database | SQLite (local) — designed for PostgreSQL |
| Tests | Vitest + Supertest |
| CI | GitHub Actions |
SQLite is used locally so the demo runs without infrastructure. The schema is written with PostgreSQL-style relational modelling in mind and can be moved by changing the provider and DATABASE_URL.
- Customers — create, list, fetch with related jobs
- Jobs — create, list, fetch, transition status through a validated state machine
- Inventory — create, list, adjust stock (with a non-negative guard), low-stock report
- Quotes — create, approve, reject; approval automatically advances the linked job
- Invoices — create (optionally linked to a quote), mark paid, list overdue
- Audit logs — automatic, queryable, written inside the same transaction as the change
See docs/data-model.md for the full entity diagram, field listing, and state-transition rules. The Prisma schema is in prisma/schema.prisma.
Entities:
Customer— fictional account that owns jobsJob— work order; moves through a validated status state machineInventoryItem— stock item with SKU, quantity, reorder levelJobPart— join row tying inventory usage to a jobQuote— pricing proposal linked to a jobInvoice— bill linked to a job (optionally a quote)AuditLog— immutable history of meaningful actions
| Method | Path | Purpose |
|---|---|---|
| GET | /health |
Health check |
| GET | /customers |
List customers |
| POST | /customers |
Create customer |
| GET | /customers/:id |
Fetch customer with jobs |
| GET | /jobs |
List jobs |
| POST | /jobs |
Create job |
| GET | /jobs/:id |
Fetch job with parts, quotes and invoices |
| PATCH | /jobs/:id/status |
Change job status (validated transitions) |
| GET | /inventory |
List inventory items |
| POST | /inventory |
Create inventory item |
| GET | /inventory/:id |
Fetch single inventory item |
| PATCH | /inventory/:id/adjust-stock |
Adjust stock by delta (cannot go below zero) |
| GET | /inventory/low-stock |
List items at or below reorder level |
| GET | /quotes |
List quotes |
| POST | /quotes |
Create quote |
| GET | /quotes/:id |
Fetch quote |
| PATCH | /quotes/:id/approve |
Approve quote (auto-advances the linked job) |
| PATCH | /quotes/:id/reject |
Reject quote |
| GET | /invoices |
List invoices |
| POST | /invoices |
Create invoice |
| GET | /invoices/:id |
Fetch invoice |
| PATCH | /invoices/:id/mark-paid |
Mark invoice paid (stamps paidAt) |
| GET | /invoices/overdue |
List overdue invoices |
| GET | /audit-logs |
List audit logs; filter by entityType, entityId, action |
Full curl examples for every endpoint — including error paths — are in docs/api-examples.md.
A typical lifecycle, top to bottom:
POST /customers— register a customerPOST /jobs— open a job for that customer (audit logjob_created)PATCH /jobs/:id/status→in_progress(audit logjob_status_changed)PATCH /inventory/:id/adjust-stockwith a negative delta as parts are used (audit loginventory_adjusted)POST /quotes— quote the workPATCH /quotes/:id/approve— quote is approved; the job auto-moves toready_for_invoice(two audit log entries written transactionally)POST /invoices— invoice the customerPATCH /invoices/:id/mark-paid— invoice is paid (paidAtstamped, audit loginvoice_marked_paid)PATCH /jobs/:id/status→completedGET /audit-logs?entityType=job&entityId=...— review the full history
Prerequisites: Node.js 20+.
git clone https://github.com/jennadebeer89-dotcom/api-workflow-management-demo.git
cd api-workflow-management-demo
cp .env.example .env
npm install
npm run setup # creates SQLite db, applies schema, seeds demo data
npm run dev # starts the server on http://localhost:3000Useful scripts:
| Command | Purpose |
|---|---|
npm run dev |
Start the API with hot reload |
npm run build |
Compile TypeScript to dist/ |
npm start |
Run the compiled server |
npm test |
Run the test suite |
npm run prisma:reset |
Drop and recreate the local database |
npm run prisma:seed |
Re-seed demo data |
npm testThe suite uses Vitest + Supertest and runs against the real Prisma + SQLite stack. Each test starts from a clean database, so the assertions reflect true end-to-end behaviour, not mocks. Coverage includes:
- Customer creation
- Job creation and state-machine validation (illegal transitions return
409) - Job status updates writing an audit log
- Inventory adjustments and the non-negative stock guard
- Quote approval moving the linked job to
ready_for_invoice - Invoice marking-paid and
paidAtstamping - Audit log creation across all important actions
- Validation errors returning useful
400responses with Zod issue details
Three ways to interact with the running API without writing any code:
docs/api-examples.md— copy/pastecurlcommands for every endpoint, including the error paths.docs/api-requests.http— a VS Code REST Client / JetBrains HTTP Client file. Open it, click "Send Request" above each block, and the responses appear inline. Later requests automatically reuse ids captured from earlier ones (@customerId,@jobId,@quoteId,@invoiceId), so the full lifecycle runs top to bottom in one pass.docs/postman-collection.json— import into Postman or Insomnia. The collection auto-captures ids into collection variables, so dependent requests chain without manual copy-paste.
To try the .http file:
# 1. Start the API in one terminal
npm run dev
# 2. Open docs/api-requests.http in VS Code (with the REST Client extension)
# and click "Send Request" above each block — top to bottom.This is a public demo project using fictional data only. It does not include real customer data, real invoices, real pricing, real company information, real API keys, credentials, or production business logic. The seed data is generic placeholder content (Acme, Globex, widgets, sprockets) used only to illustrate the workflow.
This is a focused demo, not a production system. Things deliberately left out:
- No authentication or role-based access control
- No payment integration
- No PDF generation
- No email or webhook notifications
- No frontend
- No external accounting integrations
- No multi-tenancy
- No background jobs (e.g. auto-flipping overdue invoices)
Reasonable next steps to harden this for production:
- PostgreSQL deployment (swap the Prisma
providerandDATABASE_URL) - Authentication and role-based access control (JWT, per-route authorization)
- PDF invoice generation
- Email notifications (status changes, overdue invoices)
- Frontend dashboard integration (admin UI for jobs / invoices)
- Background jobs for overdue invoices (cron / queue worker)
- External accounting system integration (Xero, QuickBooks, etc.)
- Production observability (structured logs, request IDs, metrics, tracing)
- OpenAPI / Swagger UI generated from the Zod schemas — once added, a live deployment becomes useful for recruiters.
A pure JSON API on a live URL is hard for a reviewer to evaluate — there is nothing visual to click. The higher-signal proofs are already in this repo: a green CI badge, 25 passing tests against a real database, type-checked TypeScript, a Prisma schema as the source of truth, and committed .http / Postman collections so a reviewer can hit every endpoint locally in under a minute. If a future iteration adds an interactive Swagger UI or admin frontend, a live deployment becomes worth the infrastructure cost.
This repo is part of a wider portfolio. It is the backend proof piece, demonstrating:
- Backend architecture and REST API design
- TypeScript on the server
- Relational data modelling and schema design
- Business workflow logic and state machines
- Validation, error handling, and meaningful HTTP status codes
- Audit trails as a first-class concern, written inside the same transaction as the change
- Testing and CI/CD discipline
- Safe public demo practices — no real data, no secrets, no production business logic