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).
Hub images are public on Docker Hub: derpmhichurp repositories. You can deploy with each service’s portainer-stack.yml without building locally.
| Service | Backend image | Frontend image |
|---|---|---|
| KitchenHub | derpmhichurp/kitchenhub-backend |
derpmhichurp/kitchenhub-frontend |
| VehicleHub | derpmhichurp/vehiclehub-backend |
derpmhichurp/vehiclehub-frontend |
| RetirementHub | derpmhichurp/retirementhub-backend |
derpmhichurp/retirementhub-frontend |
| PetHub | derpmhichurp/pethub-backend |
derpmhichurp/pethub-frontend |
| MailHub | derpmhichurp/mailhub-postfix, mailhub-amavisd, mailhub-dovecot |
— |
docker pull derpmhichurp/kitchenhub-backend:latest
docker pull derpmhichurp/kitchenhub-frontend:latestTags follow the same convention as CI: latest (stable release on main), beta (pre-release from other branches), or a pinned semver (e.g. 1.2.3). See each hub’s DEPLOYMENT.md where present, or portainer-stack.yml + GitHub Actions at the repo root.
- 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 - Option A — pull pre-built images: deploy
portainer-stack.ymlwithDOCKER_HUB_REGISTRY_USERNAME=derpmhichurpandIMAGE_TAG=latest(or a pinned version) - Option B — build locally:
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]



