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.
This commit is contained in:
110
README.md
110
README.md
@@ -1,96 +1,102 @@
|
||||
# EatMe — Docházka
|
||||
# EatMe — Attendance
|
||||
|
||||
Evidence docházky pro bistro EatMe. Zaměstnanci se přihlašují Google účtem a
|
||||
logují příchod / odchod / start a konec pauzy; admin (majitel) spravuje seznam
|
||||
zaměstnanců (jen e-mail, žádná hesla) a vidí souhrnné i individuální statistiky
|
||||
s grafem a exportem do CSV.
|
||||
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)
|
||||
backend/ Express + TypeScript API, SQLite (better-sqlite3), jest tests
|
||||
frontend/ React + TypeScript PWA (Vite), Google Sign-In, Zustand
|
||||
docs/ OKF (Open Knowledge Format) — architektura, datový model, provoz
|
||||
branding/ Logo a vygenerované favicony/PWA ikony z podkladu bistra
|
||||
deploy/ Šablony configů pro hosty mimo tento repo (nginx server block)
|
||||
Dockerfile Multi-stage build — jeden image pro API i frontend
|
||||
compose.yaml Produkční nasazení hotového image (viz Produkce níž)
|
||||
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)
|
||||
```
|
||||
|
||||
Vzhled je podle `~/doc/concepts/ui/light-mono-tui.md` — světlý monochromní
|
||||
"TUI" styl (mono font, ostré hrany, žádné barvy, inverze pro aktivní stav).
|
||||
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`](docs/frontend/design-system.md).
|
||||
|
||||
## Požadavky
|
||||
## Requirements
|
||||
|
||||
- Node.js 22+
|
||||
- Google Cloud projekt s nakonfigurovaným OAuth Client ID (Web application)
|
||||
— origins musí obsahovat `http://localhost:5174` pro vývoj a produkční
|
||||
doménu. Client ID se nastavuje do `GOOGLE_CLIENT_ID` (backend) a
|
||||
`VITE_GOOGLE_CLIENT_ID` (frontend) — musí být **stejné**.
|
||||
- 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**.
|
||||
|
||||
## Vývoj
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# backend
|
||||
cd backend
|
||||
cp .env.example .env # doplň GOOGLE_CLIENT_ID, ADMIN_EMAILS, JWT_SECRET
|
||||
cp .env.example .env # fill in GOOGLE_CLIENT_ID, ADMIN_EMAILS, JWT_SECRET
|
||||
npm install
|
||||
npm run dev # http://localhost:4000
|
||||
|
||||
# frontend (v druhém terminálu)
|
||||
# frontend (in a second terminal)
|
||||
cd frontend
|
||||
cp .env.example .env # VITE_GOOGLE_CLIENT_ID stejné jako backend
|
||||
cp .env.example .env # VITE_GOOGLE_CLIENT_ID same as backend
|
||||
npm install
|
||||
npm run dev # http://localhost:5174 (port je pinnutý — musí sedět s Google origin)
|
||||
npm run dev # http://localhost:5174 (port is pinned — must match the Google origin)
|
||||
```
|
||||
|
||||
Frontend v dev módu proxuje `/api/*` na backend (viz `frontend/vite.config.ts`).
|
||||
The frontend dev server proxies `/api/*` to the backend (see
|
||||
`frontend/vite.config.ts`).
|
||||
|
||||
### Typecheck / build
|
||||
### Typecheck / build / test
|
||||
|
||||
```bash
|
||||
cd backend && npm run typecheck && npm run build # -> dist/index.js (esbuild bundle)
|
||||
cd frontend && npm run build # -> dist/ (Vite, PWA)
|
||||
cd backend && npm run typecheck && npm test && npm run build # -> dist/index.js (esbuild bundle)
|
||||
cd frontend && npm run build # -> dist/ (Vite, PWA)
|
||||
```
|
||||
|
||||
## Produkce (Docker)
|
||||
## Production (Docker)
|
||||
|
||||
Jeden multi-stage `Dockerfile` v rootu postaví frontend i backend a spustí je
|
||||
jako jeden kontejner — backend servíruje API na `/api/*` a staticky sbalený
|
||||
frontend na všem ostatním.
|
||||
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.
|
||||
|
||||
Image se buildí lokálně (pro platformu cílového serveru) a na server se
|
||||
posílá hotový, ne zdrojáky:
|
||||
The image is built locally (for the target server's platform) and shipped
|
||||
to the server already built, never as source:
|
||||
|
||||
```bash
|
||||
# buildni pro platformu serveru (na Apple Silicon Macu proti x86_64 serveru
|
||||
# je --platform linux/amd64 povinné, jinak image tam vůbec nenaběhne)
|
||||
# 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 .
|
||||
|
||||
# přenes hotový image přes ssh (žádný build na serveru)
|
||||
# ship the built image over ssh (no build on the server)
|
||||
docker save eatme:latest | gzip | ssh <host> "gunzip | docker load"
|
||||
|
||||
# pošli jen compose.yaml + .env (viz .env.example) a nastartuj
|
||||
# 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` musí jít jako **build arg** (Vite ho zapéká při
|
||||
buildu, ne za běhu — v `.env` na serveru se proto řeší jen runtime proměnné).
|
||||
Pojmenovaný volume `eatme_data` (viz `compose.yaml`) drží SQLite databázi
|
||||
mimo kontejner, ať přežije redeploy.
|
||||
`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.
|
||||
|
||||
Před kontejner patří TLS-terminující reverse proxy (mimo tento repo) —
|
||||
šablona server blocku pro nginx je v `deploy/eatme.mipem.co`, proxuje na
|
||||
`http://<deploy-host>:8092`.
|
||||
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`.
|
||||
|
||||
## Datový model / provoz
|
||||
## Data model / operations
|
||||
|
||||
Zaměstnanci jsou whitelist e-mailů spravovaný adminem (`ADMIN_EMAILS` v env —
|
||||
samostatná role, není v tabulce zaměstnanců). Odebrání zaměstnance je pouze
|
||||
soft-delete (`active = 0`) — historie docházky zůstává, opětovným přidáním
|
||||
stejného e-mailu se účet reaktivuje. Statistiky se počítají po kalendářních
|
||||
měsících (`?month=YYYY-MM`), s možností listovat měsíci v adminově detailu
|
||||
zaměstnance (graf + export CSV).
|
||||
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.
|
||||
|
||||
Víc v `docs/` (OKF bundle).
|
||||
More in `docs/` (OKF bundle).
|
||||
|
||||
Reference in New Issue
Block a user