1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
A simple webapp for the family, regrouping tailor made tools (groceries,
chores).
## Features
- **Auto refresh** — the current page's data is refetched every 15 seconds
while the tab is visible, and on returning to the app after at least 10
seconds away; edit pages, hidden or offline tabs and in-flight navigations
are left untouched. No server push: polling.
- **Groceries** — two concepts: the **catalog** (every item ever added) and
the **list** (unchecked items — what to buy next). Quick add with
autocomplete, bulk category updates while planning, aisle-grouped view
while shopping. Shared across devices — every tab polls the server, so your
partner's changes land within ~15 seconds.
- **Product references** — for items like "coffee" or "pasta": one or more
reference brands with a price per unit (€/kg or €/L) and a quality score
(0–100), comparable from the item while in the store. One reference can be
promoted as the item's primary — it is listed first and is the one shown
under the item in the catalog and shopping list.
- **Categories** — items assigned to store aisles, drag to reorder the list
to match the physical layout.
- **Projects & routines** — projects ("Household", "Personal growth", …)
group recurring routines with a frequency: an interval like `2w`, or a
quota like `5/2w` (5 completions per 2-week window anchored on creation —
a closed window left unmet makes the routine En retard). Project pages
sort routines most-urgent first (À jour / À faire / En retard / Très en
retard) with one-tap "Fait", live search, and a health score (0–100) per
project and per routine, charted over time. Routines show the age of the
last completion ("fait hier", "fait il y a 5 jours") or the lateness ("3
jours de retard"); completions can be backdated to the day they actually
happened. Editing creates immutable versions and each completion records
its version — the past is never rewritten. Archiving keeps a read-only
page whose chart runs to the archive date.
- **PWA** — standalone install via `@vite-pwa/sveltekit`; works offline
after the first visit.
## Architecture
- SvelteKit (Svelte 5 runes) + adapter-node, no separate front/back. Mobile-first CSS
- SQLite via **@libsql/client** + Drizzle ORM
- Plain CSS (no framework), Vitest for tests, Prettier + ESLint flat config
- **Flat design language** (Miniflux-inspired) — hairline separators instead of
boxes, square corners, no shadows, no hover-lifts, instant state changes;
tokens in `src/styles/`, utilities in `src/app.css`
- `npm run dcd` scans source code for duplicate blocks (skips generated JSON)
- Multi-stage Docker image
- **@libsql/client over better-sqlite3** — Node 26 removed V8 API surface
(`GetPrototype`, `This` on PropertyCallbackInfo) that better-sqlite3's
native addon depends on; @libsql/client is pure JS and works out of the box.
- **Plain CSS over Tailwind** — smaller dependency footprint, no build step
for styles.
## Usage
Seed routines from the paper sheet (one-off, idempotent):
```bash
docker compose exec home node --experimental-strip-types scripts/seed-sheet1-routines.ts
```
Pull a copy of the remote database into `data.db` for local testing:
```bash
mise run db:backup
```
## Release / Deploy
Images are published to the private registry at
`container.registry.kagamino.dev`. The app password is supplied at runtime as
`AUTH_PASSWORD` in the VPS Docker Compose deployment.
```bash
# authenticate both Docker clients (once)
docker login container.registry.kagamino.dev
ssh ubuntu@feed.kagamino.dev "sudo docker login container.registry.kagamino.dev"
# start the registry, build and push the image, restart `home` on the VPS
mise run deploy
```
## TODO
- Purchase history (`checked_at` → "acheté il y a 3 jours", catalog ordered by
last bought)
- Automated database backup (cron + retention + a restore drill)
- Reference price history (price deltas on the item page)
- Today digest on the home page (routines due/late across projects)
- Offline outbox for PWA adds and toggles
- Undo a routine completion (short window; history stays append-only)
- Pre-push hook running test + check + lint before deploy
- Auto-categorize new items (LLM-assisted)
- https://automerge.org/docs/tutorial/
- Shared > Modal actions
- Result type over throws
|