Skip to content
RezoanurRahmanPublic

About

Benchflow is a durable makerspace operations desk for coordinating certified members, machine bookings, maintenance blackouts, and material reservations. It combines conflict-aware scheduling, inventory-safe reservations, auditable booking workflows, and utilization analytics in a responsive local-first workspace.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Benchflow

Benchflow is a local makerspace coordinator desk: one workspace for the certified members, machine bookings, maintenance blackouts, and material reservations that keep a shared workshop running. It is a Preact 10 + Vite 7 single-page client on a Hapi 21 server, with SQLite storage through better-sqlite3, written end to end in TypeScript.

Connected workflows:

  • Dashboard and analytics. Live metrics (active members, available machines, upcoming bookings, low-stock materials, utilization), the booking pipeline, the next bookings, and warning/info alerts, all computed from stored rows.
  • Member roster. Create members with their certifications selected at creation time, search and filter the roster, and suspend or reactivate a member.
  • Conflict-aware machine booking. A new booking is checked against member status, machine status, the machine's required certification (valid at the booking end), member overlap, machine overlap, and scheduled maintenance blackouts before materials are reserved.
  • Inventory reservations. Active bookings hold reserved stock, signed adjustments change on_hand, and completing or cancelling a booking settles stock atomically.
  • Machines, maintenance, and audit. Take machines in and out of service, schedule maintenance blackouts, and read the append-only activity trail written by every mutation. Bookings download as CSV.

The full contract, seed data, and acceptance criteria live in SPEC.md.

Not implemented in this release: there is no authentication or session handling (the desk is meant for one trusted local operator, and roles are descriptive); certifications can only be chosen when a member is created — editing or removing them afterwards is not exposed by the API or the UI; there is no JSON export bundle and no activity CSV export (the only export is GET /api/export/bookings.csv); maintenance blocks are created as scheduled and cannot be completed or cancelled through an endpoint; and booking edits are limited to status transitions (cancel and rebook to change a window or materials).

Quick start

Three commands from a fresh clone:

npm ci
npm run build
npm start

Then open http://127.0.0.1:4173. The health probe is http://127.0.0.1:4173/api/health, and npm start serves the compiled client and the API from one process, seeding the deterministic demo workshop the first time it opens a database file.

Requirements: Node.js 22.12 or newer (CI uses Node 24 LTS) and npm 10+. Only the browser tests need Chromium, installed once with npx playwright install --with-deps chromium.

Configuration

Variable Default Notes
BENCHFLOW_DB_PATH ./benchflow.sqlite SQLite file, resolved against the working directory; parent directories are created automatically
BENCHFLOW_RESET_DB unset 1 removes the target file and its -journal/-wal/-shm siblings before opening a file database; ignored for :memory:
PORT 4173 HTTP port for the API and the production client
HOST 0.0.0.0 Bind address
BENCHFLOW_CLIENT_DIR dist/client Optional override for the built client directory that is served as static assets

The database is a single file, so a backup is a file copy — stop the server first, or use sqlite3 benchflow.sqlite ".backup backup.sqlite" while it runs.

Commands

Command What it does
npm run dev Vite dev server on http://127.0.0.1:5173, proxying /api to http://127.0.0.1:4173
npm run dev:server Build the server and run it so /api is available while developing
npm run build Compile the server to dist/server and bundle the client to dist/client
npm start Run node dist/server/index.js (requires npm run build first)
npm run lint ESLint over src, tests, and config files
npm run format:check Prettier check
npm run typecheck tsc --noEmit for the client, shared contracts, and tests
npm test Vitest unit and integration suites
npm run test:unit Vitest over tests/unit
npm run test:integration Vitest over tests/integration (real Hapi server and a real SQLite file)
npm run test:e2e Playwright Chromium against the built app on port 4173

API

All routes live under /api. Every JSON response uses one envelope — { "data": ... } on success — except GET /api/health, which returns a raw status object, and GET /api/export/bookings.csv, which returns text/csv. Failures always answer with the same JSON shape, including unknown /api routes:

{
  "error": {
    "code": "CONFLICT",
    "message": "ShopBot CNC Router is already booked by booking-ava-cnc overlapping 2026-10-15 from 09:30 to 10:30.",
    "fields": {
      "bookingId": "booking-ava-cnc",
      "startsAt": "2026-10-15T09:00:00.000Z",
      "endsAt": "2026-10-15T10:30:00.000Z"
    },
    "details": {
      "bookingId": "booking-ava-cnc",
      "startsAt": "2026-10-15T09:00:00.000Z",
      "endsAt": "2026-10-15T10:30:00.000Z"
    }
  }
}

fields and details are aliases that carry structured context when the failure has any.

Method Route Input Success Failure codes
GET /api/health — 200 raw { status, service, storage, version, uptimeSeconds } —
GET /api/dashboard — 200 { data: DashboardData } —
GET /api/analytics — 200 { data: Analytics } —
GET /api/certifications — 200 { data: Certification[] } —
GET /api/members ?q= (name/email search), ?status=active|suspended 200 { data: Member[] } VALIDATION_ERROR
POST /api/members { name, email, role?, certificationIds? } — up to 5 certifications selected at creation 201 { data: Member } VALIDATION_ERROR, CONFLICT (email already registered)
PATCH /api/members/{id}/status { status: "active" | "suspended" } 200 { data: Member } VALIDATION_ERROR, NOT_FOUND, ACTIVE_BOOKING
GET /api/machines — 200 { data: Machine[] } —
PATCH /api/machines/{id}/status { status: "available" | "maintenance" | "retired" } 200 { data: Machine } VALIDATION_ERROR, NOT_FOUND, ACTIVE_BOOKING
POST /api/machines/{id}/maintenance { startsAt, endsAt, reason } 201 { data: MaintenanceBlock } VALIDATION_ERROR, NOT_FOUND, CONFLICT (booking/blackout overlap), MACHINE_UNAVAILABLE (retired)
GET /api/maintenance — 200 { data: MaintenanceBlock[] } —
GET /api/materials — 200 { data: Material[] } —
PATCH /api/materials/{id}/stock { delta, reason } — signed adjustment 200 { data: Material } VALIDATION_ERROR, NOT_FOUND, CONFLICT (below zero or below reserved stock)
GET /api/bookings ?status=, ?from=, ?to= (ISO date or date-time, half-open window overlap) 200 { data: Booking[] } VALIDATION_ERROR
POST /api/bookings { memberId, machineId, startsAt, endsAt, purpose, materials? } 201 { data: Booking } (status requested) VALIDATION_ERROR, NOT_FOUND, MEMBER_SUSPENDED, MACHINE_UNAVAILABLE, CERTIFICATION_REQUIRED, CONFLICT, INSUFFICIENT_STOCK
PATCH /api/bookings/{id}/status { status } — allowed transitions only 200 { data: Booking } VALIDATION_ERROR, NOT_FOUND, INVALID_TRANSITION, CONFLICT (stock settlement)
GET /api/activity ?limit= (1–100, default 50) 200 { data: Activity[] } newest first VALIDATION_ERROR
GET /api/export/bookings.csv — 200 text/csv attachment benchflow-bookings.csv —

Stable machine-readable error codes: VALIDATION_ERROR (400), NOT_FOUND (404), CONFLICT, CERTIFICATION_REQUIRED, INSUFFICIENT_STOCK, INVALID_TRANSITION, MEMBER_SUSPENDED, MACHINE_UNAVAILABLE, and ACTIVE_BOOKING (all 409); unexpected faults become INTERNAL_ERROR (500) without leaking details.

Data model and seed

SQLite tables: certifications, members, member_certifications, machines, materials, maintenance_blocks, bookings, booking_materials, and activity. reserved on materials is a stored column kept transactionally consistent with non-terminal bookings, and available = onHand - reserved.

The deterministic seed runs only when the corresponding tables are empty, uses fixed ids and the reference day 2026-10-13, and contains:

  • 5 certifications: cert-wood, cert-cnc, cert-laser, cert-metal, cert-print.
  • 5 members: member-ava (Ava Chen, manager, active), member-ben (Ben Ortiz, active), member-cora (Cora Malik, suspended), member-dee (Dee Nakamura, active), member-eli (Eli Thompson, suspended).
  • 5 machines: machine-cnc-01 ShopBot CNC Router (available, needs cert-cnc, 45/h), machine-laser-01 Epilog Laser Cutter (available, cert-laser, 30/h), machine-lathe-01 Jet Metal Lathe (maintenance, cert-metal, 40/h), machine-printer-01 Prusa 3D Printer (retired, cert-print, 25/h), machine-saw-01 Panel Saw (available, cert-wood, 20/h).
  • 5 materials: material-plywood, material-mdf, material-filament, material-aluminium, material-acrylic — including PLA filament below its reorder point, which drives the low-stock alert.
  • 4 bookings across 2026-10-09 to 2026-10-20: two completed, one confirmed, one requested. The active ones reserve 6 sheets of plywood and 3 sheets of acrylic.
  • 1 maintenance block: block-lathe-service on machine-lathe-01, 2026-10-18 08:00–12:00 UTC.
  • 13 activity entries, plus one new row for every later mutation.

Testing

  • npm test runs the Node-based Vitest suites. tests/unit covers contracts, transition tables, conflict and cost math, and store rules; tests/integration boots the real Hapi server against a temporary .tmp/*.sqlite file and verifies persistence, transactionality, and error envelopes.
  • npm run test:e2e runs the Playwright journey suite against the production build; the config starts npm start on port 4173 with BENCHFLOW_DB_PATH=.tmp/e2e.sqlite and BENCHFLOW_RESET_DB=1, so every run begins from the same seeded workshop.
  • CI (.github/workflows/ci.yml) runs lint, format:check, typecheck, the unit and integration suites, the production build, the Playwright suite, and a packaged-server smoke test that fails with the server log when /api/health does not answer within 30 seconds.

License

MIT — see LICENSE.

About

Benchflow is a durable makerspace operations desk for coordinating certified members, machine bookings, maintenance blackouts, and material reservations. It combines conflict-aware scheduling, inventory-safe reservations, auditable booking workflows, and utilization analytics in a responsive local-first workspace.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages