Michal Pemcak 94933cac5c Update OKF docs bundle, README, and CLAUDE.md for today's features
Documents the shift planning and closure/payroll modules (new tables,
routes, stores), the dark redesign, and the docker-compose-broken-host
workaround. Adds CLAUDE.md pointing agents at docs/. Translates README to
English and keeps host-specific infrastructure details out of the repo.
2026-08-16 18:41:11 +02:00

EatMe — Attendance

Internal staff system for the EatMe bistro. Employees sign in with Google, log clock-in/out and breaks, sign up for shifts, and confirm their month at the end of it; the admin (owner) manages the employee list and their hourly rates, plans shifts, approves closures, and runs payroll (tips, bonuses, CSV export).

backend/       Express + TypeScript API, SQLite (better-sqlite3), jest tests
frontend/      React + TypeScript PWA (Vite), Google Sign-In, Zustand
docs/          OKF (Open Knowledge Format) bundle — architecture, data model, ops
gscript/       Original Google Apps Script version (reference only, not part of the running app)
branding/      Logo and generated favicons/PWA icons from the bistro's artwork
deploy/        Config templates for hosts outside this repo (nginx server block)
Dockerfile     Multi-stage build — one image for API and frontend
compose.yaml   Production deployment of the built image (see Production below)

The look is dark, modern, sharp-edged (no rounded corners), with a single amber accent used sparingly — no colored accent borders. Details in docs/frontend/design-system.md.

Requirements

  • Node.js 22+
  • A Google Cloud project with an OAuth Client ID configured (Web application) — authorized origins must include http://localhost:5174 for dev and the production domain. The client ID goes into GOOGLE_CLIENT_ID (backend) and VITE_GOOGLE_CLIENT_ID (frontend) — they must be identical.

Development

# backend
cd backend
cp .env.example .env   # fill in GOOGLE_CLIENT_ID, ADMIN_EMAILS, JWT_SECRET
npm install
npm run dev             # http://localhost:4000

# frontend (in a second terminal)
cd frontend
cp .env.example .env    # VITE_GOOGLE_CLIENT_ID same as backend
npm install
npm run dev              # http://localhost:5174 (port is pinned — must match the Google origin)

The frontend dev server proxies /api/* to the backend (see frontend/vite.config.ts).

Typecheck / build / test

cd backend  && npm run typecheck && npm test && npm run build   # -> dist/index.js (esbuild bundle)
cd frontend && npm run build                                     # -> dist/ (Vite, PWA)

Production (Docker)

One multi-stage Dockerfile at the repo root builds both frontend and backend and runs them as a single container — the backend serves the API on /api/* and the statically-built frontend on everything else.

The image is built locally (for the target server's platform) and shipped to the server already built, never as source:

# build for the server's platform (on an Apple Silicon Mac targeting an
# x86_64 server, --platform linux/amd64 is required or the image won't
# run there at all)
docker build --platform linux/amd64 \
  --build-arg VITE_GOOGLE_CLIENT_ID=<client-id> \
  -t eatme:latest .

# ship the built image over ssh (no build on the server)
docker save eatme:latest | gzip | ssh <host> "gunzip | docker load"

# send just compose.yaml + .env (see .env.example) and start it
scp compose.yaml <host>:~/eatme/compose.yaml
ssh <host> "cd ~/eatme && docker compose up -d"

VITE_GOOGLE_CLIENT_ID has to go in as a build arg (Vite bakes it in at build time, not runtime — .env on the server only handles runtime vars). The named volume eatme_data (see compose.yaml) keeps the SQLite database outside the container so it survives a redeploy.

A TLS-terminating reverse proxy belongs in front of the container (outside this repo) — an nginx server block template lives at deploy/eatme.mipem.co, proxying to http://<deploy-host>:8092.

Data model / operations

Employees are an email whitelist managed by the admin (ADMIN_EMAILS env var — a separate role, not a row in the employees table). Removing an employee is a soft delete (active = 0) — attendance history stays, and re-adding the same email reactivates the account. Employees also have a versioned hourly rate, sign up for shifts from a weekly template, and confirm each calendar month before the admin locks it and runs payroll.

More in docs/ (OKF bundle).

Description
EatMe bistro attendance, shift planning, and payroll system
Readme 3.3 MiB
Languages
HTML 49.8%
JavaScript 34%
TypeScript 14.8%
CSS 1.3%
Dockerfile 0.1%