feat: založení základní stránky příjem/výdej + import a statistiky

This commit is contained in:
Ondřej Anděl
2026-09-07 14:58:49 +02:00
commit a5711f3e1e
98 changed files with 15505 additions and 0 deletions
+105
View File
@@ -0,0 +1,105 @@
# Food Tracer
Aplikace pro evidenci snědených jídel a útraty za jídlo. Ke každému jídlu se dá
vedle názvu a zdroje uložit i cena a kalorie, takže jde zpětně zjistit, kolik
člověk za jídlo utratil za den, měsíc nebo rok.
Umí naimportovat měsíční přehled vyexportovaný ze stránky statistik
[Luncheru](../Luncher) — ve formátu XLSX, CSV i JSON.
## Struktura
```
types/ → Sdílené TypeScript typy generované z OpenAPI (zdroj pravdy: types/api.yml)
server/ → Express 5 backend (Node.js 22, ts-node)
client/ → React 19 frontend (Vite 7, React Bootstrap)
```
Package manager: **Yarn Classic**. Každá složka má vlastní `package.json`.
## Rozjetí
```bash
cd types && yarn install && yarn openapi-ts # typy je nutné vygenerovat první
cd ../server && yarn install
cd ../client && yarn install
```
Do `server/.env.development` patří `JWT_SECRET` o délce alespoň 32 znaků
(šablona je v `server/.env.template`).
## Vývoj
```bash
./run_dev.sh # vše naráz v tmuxu (Linux/macOS)
.\run_dev.ps1 # dvě PowerShell okna (Windows)
```
Nebo ručně ve dvou terminálech:
```bash
cd server && NODE_ENV=development yarn startReload # port 3001
cd client && yarn start # port 3000, proxy /api → 3001
```
## Testy a build
```bash
cd server && yarn test # Jest, in-memory úložiště
cd server && yarn build # tsc → server/dist
cd client && yarn build # tsc --noEmit + vite build → client/dist
```
## Nasazení
```bash
JWT_SECRET=... docker compose up --build
```
Produkčně běží aplikace nad Redisem, ve vývoji nad JSON souborem
(`server/data/db.json`). Viz `server/.env.template`.
## Den: příjem a výdej
Přehled dne má dvě záložky:
- **Příjem** — co jste snědli, s cenou, gramáží a kaloriemi.
- **Výdej** — pohyb. Kroky, minuty, kilometry nebo opakování; z množství a
spotřeby na 100 jednotek se dopočtou spálené kalorie (10 000 kroků ≈ 400 kcal).
Opakované tréninky se dají uložit jako **šablonu***Workout day 1* pak stačí
jedním kliknutím založit do dne celý, místo zadávání cviku po cviku. Založené
položky jsou samostatné, takže je jde doupravit, aniž by se změnila šablona.
Nahoře je **bilance dne**: `příjem (klidový výdej + pohyb)`. Klidový výdej
(bazální metabolismus) se nastavuje v *Nastavení* — bez něj se porovnává jen
jídlo proti pohybu a nejde o skutečný deficit, na což aplikace upozorní.
## Kalorie a gramáž
Ke každému jídlu jde vyplnit **cenu za 100 g** a z ní se dopočítá **gramáž**
(u TechToweru typicky 44 Kč/100 g). Gramáž jde kdykoli přepsat ručně a každá
položka má vlastní sazbu — hlavní jídlo a salát s jiným cenováním se nepletou.
Sazby podniků se nastavují v *Nastavení* a při výběru zdroje se předvyplní.
Z gramáže a **energie na 100 g** se pak dopočítají kalorie. Hodnotu nabídne
tlačítko *Najít kalorie*:
- z **vlastní knihovny** — co jste jednou zadali, aplikace si pamatuje pod názvem
jídla a příště nabídne sama,
- z **Open Food Facts** (otevřená databáze, bez klíče),
- odkazem na **KalorickéTabulky.cz**, které veřejné API nemají — otevřou se
v novém panelu a název jídla se zkopíruje do schránky, hodnotu opíšete ručně.
Když je externí databáze nedostupná, hledání nespadne — zůstane vlastní knihovna.
## Import z Luncheru
Na stránce **Statistiky** je tlačítko *Import z Luncheru*. Stačí nahrát soubor
stažený ze statistik Luncheru:
- Záznamy se rozdělí do dnů, ke kterým patří (export je typicky za celý měsíc).
- Zakládají se jako **oběd**, protože Luncher řeší výběr obědů. Chod jde při
importu změnit a jednotlivá jídla pak upravit v přehledu dne.
- Před uložením se ukáže náhled toho, co se založí.
- Opakovaný import stejného měsíce data nezduplikuje.