Interný systém pre kaviareň s dvoma prevádzkami: rozpis zmien, dochádzka, mesačný výkaz pre účtovníka, receptúry a sklad. Appku používa tím v bežnej prevádzke. Robil som ju popri práci baristu v tej istej kaviarni.
- Dostupnosti — zamestnanci zadajú, kedy môžu budúci týždeň pracovať (dni, časy, priorita, max. počet zmien).
- Rozpis zmien — manažér vygeneruje rozpis jedným tlačidlom, upraví ho a zverejní. Rozpis počíta solver na backende.
- Moje zmeny — zamestnanec si zapisuje odpracované hodiny a neprítomnosti (dovolenka, PN, OČR, lekár). Zmeny cez polnoc sa rátajú správne.
- Výkaz práce — mesačný prehľad za zamestnanca a prevádzku s hodinami v sobotu, nedeľu, vo sviatok a v noci, export do PDF pre účtovníka.
- Zamestnanci — pozvánky e-mailom, pracovnoprávny vzťah zvlášť pre každú prevádzku (každá má vlastné IČO), archivácia namiesto mazania.
- Receptúry — recepty podľa prevádzky, fotky, vyhľadávanie, najčastejšie otvárané.
- Sklad — stav položiek, upozornenie pod minimom, počítadlo +/-.
| Časť | Technológie |
|---|---|
Frontend (public/) |
HTML, CSS, JavaScript bez frameworku; PWA (inštalovateľná na mobil) |
| Databáza a prihlásenie | Supabase — PostgreSQL, Auth, Storage, Row Level Security |
Backend (schedule_generator/) |
Python, FastAPI — generovanie rozpisu, pozvánky, archivácia |
| Hosting | Render |
Frontend číta a zapisuje priamo do Supabase; čo kto smie vidieť, určujú RLS
politiky v databáze (supabase/schema.sql). Backend s service key sa volá len
na veci, ktoré prehliadač urobiť nesmie: generovanie rozpisu, pozvánka
a zablokovanie účtu.
Rozpis je úloha s tvrdými pravidlami (dostupnosť, minimum a maximum ľudí na zmene, barista na každej zmene, max. počet dní) a mäkkými (zamestnanec na TPP má mať svoje dni, brigádnici rovnomerne). Solver ide v dvoch krokoch:
- Greedy — najprv dni s najmenej dostupnými ľuďmi, v rámci dňa ľudia s najmenej dostupnými dňami. Rýchlo dá rozpis, ktorý nemusí byť platný.
- Min-Conflicts repair — vyberie porušené pravidlo, vyskúša ťahy, ktoré ho môžu opraviť (pridať, odobrať, vymeniť človeka), a ponechá najlepší. Opakuje, kým sa rozpis zlepšuje.
Solver (schedule_generator/solver) plánuje celé dni; časy zmeny sú
otváracie hodiny prevádzky.
Databáza — v novom Supabase projekte spusti v SQL editore:
supabase/schema.sql
supabase/seed/holidays.sql
supabase/seed/demo.sql (voliteľné, ukážková prevádzka)
Frontend — doplň URL a anon key do public/js/supabase-client.js a spusti
statický server v public/ (napr. Live Server na porte 5500).
Backend:
pip install -r schedule_generator/requirements.txt
cp .env.example .env # doplň SUPABASE_URL a SUPABASE_SERVICE_ROLE_KEY
cd schedule_generator
uvicorn api.main:app --reload
Testy a benchmark:
cd schedule_generator
pytest # solver a API
python benchmark_solver.py # 16 scenárov, čas a úspešnosť
Databázová schéma vznikala postupne v 24 migráciách; tu je zlúčená do jedného súboru v stave, v akom beží v produkcii.
An internal system for a café with two locations: shift scheduling, time tracking, a monthly timesheet for the accountant, recipes and inventory. The team uses it day to day. I built it while working as a barista at the same café.
The code, comments and UI are in Slovak.
- Availability — employees enter when they can work next week (days, hours, priority, max. number of shifts).
- Shift schedule — the manager generates a schedule with one click, edits it and publishes it. The schedule is computed by a solver on the backend.
- My shifts — employees log worked hours and absences (vacation, sick leave, doctor). Shifts past midnight are counted correctly.
- Timesheet — monthly overview per employee and location, with hours on Saturdays, Sundays, public holidays and at night; PDF export for the accountant.
- Employees — email invitations, employment contract type per location (each location is a separate employer), archiving instead of deleting.
- Recipes — per location, with photos, search and most viewed.
- Inventory — stock levels, low-stock warnings, +/- counter.
| Part | Stack |
|---|---|
Frontend (public/) |
HTML, CSS, vanilla JavaScript; installable PWA |
| Database and auth | Supabase — PostgreSQL, Auth, Storage, Row Level Security |
Backend (schedule_generator/) |
Python, FastAPI — scheduling, invitations, archiving |
| Hosting | Render |
The frontend talks to Supabase directly; access is enforced by RLS policies
in the database (supabase/schema.sql). The backend holds the service key and
is only used for what the browser must not do: generating schedules, sending
invitations and blocking accounts.
Scheduling has hard rules (availability, min/max staff per shift, a barista on every shift, max days per week) and soft ones (full-time staff get their days, part-timers are balanced). The solver works in two steps:
- Greedy — days with the fewest available people first; within a day, the people with the fewest available days first. Fast, but not always valid.
- Min-Conflicts repair — pick a violated rule, try moves that could fix it (add, remove or swap a person) and keep the best one. Repeat while the schedule improves.
The solver (schedule_generator/solver) plans whole days; shift times are the
location's opening hours.
Run supabase/schema.sql, supabase/seed/holidays.sql and optionally
supabase/seed/demo.sql in the SQL editor of a new Supabase project. Fill in
the URL and anon key in public/js/supabase-client.js and serve public/
with any static server. For the backend and tests, see the commands in the
Slovak section above — they are the same.
The database schema grew over 24 migrations; here it is merged into a single file matching production.
Dominik Ivanov