- Python 43.1%
- HTML 31.9%
- CSS 17.1%
- JavaScript 7.4%
- Dockerfile 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Push Docker Image / push (push) Successful in 5m2s
|
||
| .forgejo/workflows | ||
| .impeccable | ||
| core | ||
| docker | ||
| hearth | ||
| locale/pl/LC_MESSAGES | ||
| static | ||
| templates | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .python-version | ||
| bun.lock | ||
| CLAUDE.md | ||
| DESIGN.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| manage.py | ||
| package-lock.json | ||
| package.json | ||
| PRODUCT.md | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
🔥 Hearth
A real-time household management app: a shared shopping list, a weekly meal planner, and a recipe cookbook — with live sync between household members over WebSockets. Built from the Hearth design prototype.
Charcoal · cream · flame-orange, Archivo type, grain-textured surfaces.
Stack
- Django 6 (full-stack: templates + forms), managed with uv
- HTMX for reactivity — mutations swap server-rendered fragments
- Django Channels (
channels+channels-redis+daphne) for WebSocket sync - Tailwind CSS 4 (CSS-first
@theme), built with the Tailwind CLI via Node - Postgres + Redis in production; SQLite + in-memory channel layer for dev
- Docker (multi-stage) for packaging; Daphne (ASGI) + WhiteNoise for static
How real-time sync works
Every mutation is an HTMX POST that (1) returns the affected region as an
hx-swap-oob fragment to update the actor instantly, and (2) broadcasts the same
update to the household's Channels group so the partner's browser applies it too.
HTML (not JSON) travels over the socket, so HTMX's ws extension swaps it directly.
- Shopping: the whole board is re-rendered and OOB-swapped. Search + category filtering is client-side over the full board, so a partner's in-progress search is never clobbered by an incoming sync.
- Planner: a tiny "ping" element is OOB-swapped in and self-fires an HTMX GET, so each client reloads its own week — never yanked to the actor's week.
Local development
Requirements: Python 3.13 (via uv), Node 20+.
uv sync # Python deps
npm install # front-end toolchain
npm run build # vendor HTMX/font + build Tailwind CSS
uv run python manage.py migrate
uv run python manage.py seed_hearth
uv run python manage.py runserver
Open http://127.0.0.1:8000 and sign in as you / ada (password hearth123).
runserver serves ASGI (WebSockets included) because daphne is first in
INSTALLED_APPS. In dev the channel layer is in-memory (single process), so sync
works across tabs without Redis.
While iterating on styles, run the CSS watcher in another terminal:
npm run watch:css
To regenerate the placeholder recipe/hero images:
uv run --with pillow python scripts/gen_assets.py
Production (Docker)
cp .env.example .env # set SECRET_KEY, ALLOWED_HOSTS, domain…
docker compose up --build
Compose runs three services — web (Daphne on :8000), db (Postgres), redis (channel layer) — and the entrypoint migrates, seeds, and collects static on start. App at http://localhost:8000.
Project layout
hearth/ Django project (settings, asgi with Channels routing, urls)
core/
models.py Household, Membership, ShoppingItem, Recipe*, MealEntry
views.py HTMX views: mutations return OOB fragments + broadcast
services.py household resolution, week math, board/planner view-models
consumers.py HouseholdConsumer (AsyncWebsocketConsumer, HTML over ws)
realtime.py broadcast() → channel layer group_send
constants.py 12 categories + 4 meal rows
seed_data.py recipes + demo data (from the prototype)
templates/ base shell, per-view pages, partials/ (fragments + modals)
assets/css/ Tailwind input (@theme tokens, keyframes, components)
static/ build output + committed images (served by WhiteNoise)
scripts/ vendor.mjs (HTMX/font), gen_assets.py (images)