A monorepo of self-hosted web applications. KitchenHub, VehicleHub, and RetirementHub each ship a Node.js + Express REST API, a React + Vite SPA, PostgreSQL, and Docker-friendly layouts. PetHub is the same React + Vite and PostgreSQL pattern, but its API is Python + Flask (Gunicorn in the published backend image). MailHub is a separate multi-container mail stack (see MailHub README).
Screenshots use demo-style data. Click a thumbnail to open that hub’s README.
| KitchenHub | VehicleHub | RetirementHub | PetHub |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
MailHub — SMTP, filtering, and IMAP/LMTP stack (no app UI screenshots in this repo).
Each app has its own API, UI, and database schema. They are intended to run on a Docker host with a reverse proxy and TLS in front (details are up to your environment).
- KitchenHub — Shopping lists with optional store layout ordering, recipes, and related data
- VehicleHub — Vehicle maintenance and service history
- RetirementHub — Retirement-oriented budgeting, savings limits, and projections
- MailHub — Multi-container mail stack (SMTP, filtering, IMAP/LMTP). Different layout than the other hubs
- PetHub — Pet activity tracking (ports backend
8120, frontend8130)
- Backend: Node.js + Express (KitchenHub, VehicleHub, RetirementHub); Python + Flask (PetHub), with Gunicorn as the WSGI server in its Docker image
- Frontend: React + Vite for KitchenHub, VehicleHub, RetirementHub, and PetHub (often served by nginx in production)
- Database: PostgreSQL
- Deployment: Docker / Compose (see each service)
Default ports are spaced to avoid clashes:
- KitchenHub: backend
8080, frontend8081 - VehicleHub: backend
8090, frontend8091 - RetirementHub: backend
8100, frontend8110 - PetHub: backend
8120, frontend8130 - Future services: continue the pattern (e.g. +10 per service)
Typical setup:
- Host — Linux with Docker (or similar) and persistent volumes for databases and app data
- Database — PostgreSQL (container or external)
- Edge — A reverse proxy terminating TLS and routing hostnames to the right containers (Caddy, nginx, Traefik, HAProxy, etc.)
- DNS / certificates — Whatever you use for names and ACME (router, separate DNS, internal DNS, etc.)
Each service directory includes docker-compose.yml, optional portainer-stack.yml, env.example, and a README.md with concrete steps.
cd <service>cp env.example .envand set database (and other) variables- Apply
database/schema.sql(and migrations if upgrading) withpsql docker compose up -d --build- Point your proxy at the published ports and add DNS names as needed
Backends expose /api/health for readiness checks.
.
├── common/ # Shared code
│ ├── database/
│ └── api/
├── kitchenhub/
├── vehiclehub/
├── retirementhub/
├── mailhub/
├── pethub/
└── README.md
The repo includes reusable seed scripts for screenshot/demo environments:
kitchenhub/database/demo-seed.sqlvehiclehub/database/demo-seed.sqlretirementhub/database/demo-seed.sqlpethub/database/demo-seed.sql
Run these from the repo root to apply demo data to the hosted demo databases:
$env:PGPASSWORD="<db-password>"docker run --rm -v "${PWD}:/workspace" -e PGPASSWORD="$env:PGPASSWORD" postgres:16 psql -h <db-host> -p 5432 -U <db-user> -d demo_kitchenhub -f /workspace/kitchenhub/database/demo-seed.sql
docker run --rm -v "${PWD}:/workspace" -e PGPASSWORD="$env:PGPASSWORD" postgres:16 psql -h <db-host> -p 5432 -U <db-user> -d demo_vehiclehub -f /workspace/vehiclehub/database/demo-seed.sql
docker run --rm -v "${PWD}:/workspace" -e PGPASSWORD="$env:PGPASSWORD" postgres:16 psql -h <db-host> -p 5432 -U <db-user> -d demo_retirementhub -f /workspace/retirementhub/database/demo-seed.sql
docker run --rm -v "${PWD}:/workspace" -e PGPASSWORD="$env:PGPASSWORD" postgres:16 psql -h <db-host> -p 5432 -U <db-user> -d demo_pethub -f /workspace/pethub/database/demo-seed.sqlNotes:
- The seed scripts are idempotent and safe to rerun.
- Apply each service schema once before seeding a fresh database:
kitchenhub/database/schema.sqlvehiclehub/database/schema.sqlretirementhub/database/schema.sqlpethub/database/schema.sql
common/database/db-config.js — PostgreSQL pool
common/api/api-client.js — API client reference for frontends
Backends import from common via relative paths, for example:
const { createDbPool } = require('../../common/database/db-config');- Run services behind TLS at the edge; do not commit real
.envfiles or secrets - Restrict database access to application containers on internal networks
- For MailHub, keep credentials in env or mounted secrets, not in public docs
[Add your license here]



