A local, single-user web app that replaces a spreadsheet-based weekly schedule for a quick-service / fast-food store. Runs entirely on your machine — no accounts, no cloud, no deployment. Works equally well on a phone and a computer/tablet.
It's a two-layer scheduler:
- Layer 1 — Shifts. For each employee, every day is a state:
OFF,ON CALL,OPEN(store opening time),CLOSE(store closing time), or aTIMEDshift with explicit start/end. Cells can carry a note ("Truck", "Cake") and an uncertain end ("5/6"). - Layer 2 — Station assignments. Each day has a fixed list of stations (FRONT, DT ORDER, HOT, SAND 1…). Each station is assigned to one or two working employees.
The critical rule the app enforces: you can only assign someone to a station on a day they're actually working. Off-shift staff are never assignable; on-call staff can be assigned but are flagged as tentative.
- CSV importer for the manager's existing messy spreadsheet, with a
post-import review screen listing anything that couldn't be parsed
cleanly (
sample-schedule.csvis included to try it). - Per-day store hours and per-day station availability — e.g. the store opens 4:00 AM weekdays / 4:30 AM Saturday / 5:00 AM Sunday (closing 8:00 PM), and DELIVERY + SAND 3 run on weekends only.
- Week view (desktop): two stacked grids (staff × days, stations × days) with sticky headers, color-coded shift states, and a quick editor.
- Day view (mobile): one day at a time with large tap targets and a bottom-sheet editor.
- Full-assist auto-suggest: proposes station assignments from each day's working pool, using preferred roles + learned affinity, and learns every time you confirm or override an assignment.
- Live coverage & conflict panel: uncovered required stations, unassigned workers, off-but-assigned (blocked), on-call assigned, missing opener/closer, and uncertain shifts.
- Copy previous week, CSV/JSON export, and a clean print view.
- Editable employees, stations, and store settings (open/close times, week start day).
Requires Node 18+ (developed on Node 22).
npm install
npm run devThis starts both the API (Express, port 3001) and the web app
(Vite, port 5173) together via concurrently. Open:
On first run the data file (schedule.json) is created and seeded with the
store's current roster, default stations, and store hours, plus an empty
current week — ready to start scheduling. Run npm run reset (then restart)
to wipe all data and re-seed from scratch.
| Command | What it does |
|---|---|
npm run dev |
Run API + web together (development) |
npm run build |
Type-check and build the production frontend |
npm run typecheck |
Type-check only |
npm run start |
Run the API server once (no watch) |
npm run reset |
Delete all data (re-seeds on next start) |
- Frontend: React + TypeScript + Vite + Tailwind CSS.
- Backend: Node + Express, persisting to a local
schedule.jsonfile (so data survives restarts). A plain JSON file is used instead of a native SQLite binding sonpm installneeds no compiler or build tools and works the same on macOS, Linux, and Windows. It's still trivial to back up (copy the file) and inspect. - Shared logic (
shared/): the parser, time helpers, coverage checks, and the auto-suggest algorithm are pure functions reused by both the server (import/seed) and the client (live recompute).
server/ Express API, JSON store, CSV importer
shared/ Types + pure logic (parser, time, coverage, suggest)
src/ React app (components, store, API client)
sample-schedule.csv Example messy CSV for trying the importer
All data lives in schedule.json in the project root. To back up, copy that
file. To start fresh, run npm run reset (or delete the file) — the app
re-seeds the roster, stations, and hours on the next launch. (It's git-ignored
so your data never gets committed.)
Row 1: (blank), date, date, … (one per day column)
Row 2: NAME, SUN, MON, TUE, WED, THU, FRI, SAT
Rows : employee name, then a shift cell per day
(blank row)
Rows : station name, then assignee(s) per day ("Sonal/Agna" splits a station)
The importer is deliberately defensive — it understands OPEN to 10,
1 to close, 4.30 to 12 (dots = colons), 5/6 (uncertain end), OfF,
call?, parenthetical notes like PARAS(Truck), and normalizes
DOORDASH/UBER → DELIVERY and SAND → SAND 1. Anything ambiguous is
imported best-effort and surfaced on the review screen.