Daily Quote app
Go to file
Daily Quote Builder a9430702b4
All checks were successful
CI / build (push) Successful in 1m12s
Fix Gitea Actions runner: attach job containers to compose network for checkout DNS
2026-07-20 16:52:50 +00:00
.gitea/workflows Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00
backup Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00
client Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00
db Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00
gitea Fix Gitea Actions runner: attach job containers to compose network for checkout DNS 2026-07-20 16:52:50 +00:00
observability Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00
server Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00
systemd Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00
.env.example Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00
.gitignore Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00
docker-compose.yml Fix Gitea Actions runner: attach job containers to compose network for checkout DNS 2026-07-20 16:52:50 +00:00
README.md Daily Quote: Vite/React + MUI M3 frontend, Express API, Postgres, Zitadel auth, observability, backups 2026-07-20 16:43:47 +00:00

Daily Quote

A small full-stack "quote of the day" app, built for the privatecloud VM private-cloud-daily-quote.

Stack

  • Frontend: Vite + React, styled with MUI using a Material Design 3 theme (color roles, type scale, shape/elevation).
  • API: Express (Node.js), serving both /api/* and the built SPA on port 3000.
  • Database: Postgres 16, run via Docker Compose (quotes, users, favorites tables — see db/init.sql).
  • Platform auth: Zitadel, self-hosted via Docker, OIDC Authorization Code + PKCE. Gates "submit a quote" and "favorites"; browsing is public.
  • Git hosting: Gitea, self-hosted via Docker (this repo's origin).
  • CI/CD: Gitea Actions, using a local act_runner container. See .gitea/workflows/ci.yml.
  • Observability: prom-client metrics at /api/metrics, scraped by Prometheus, visualized in a provisioned Grafana dashboard.
  • Backup: nightly pg_dump via a systemd timer (quoteapp-backup.timer), 7-day retention, dumps to ~/backups.

Local services (Docker)

Service Internal port Host port Notes
Postgres 5432 5432 (loopback only) app + zitadel databases
Zitadel 8080 8080 public via https://<host>:8080
Gitea 3000 3001 public via https://<host>:3001
Gitea SSH 22 2222 (loopback only)
act_runner - - registered against Gitea Actions
Prometheus 9090 9090 (loopback only)
Grafana 3000 3002 public via https://<host>:3002, admin/admin

Bring the stack up with:

docker compose up -d

Running the app

The app itself runs directly on the VM (not in Docker) as a systemd service on port 3000:

sudo systemctl status quote-app

To rebuild after a frontend change:

cd client && npm run build
sudo systemctl restart quote-app

Auth notes

Zitadel is reachable at https://<vm-host>:8080. Since exe.dev's proxy only marks one port ("3000", the app) fully public, signing in requires being an authorized user of this workspace to reach the Zitadel login page on port 8080 — browsing and reading quotes on the main app is public regardless. A demo user (demo) was created for testing; see .zitadel-demo-user (not committed) for its password.

Backups

./backup/backup.sh          # run manually
systemctl list-timers quoteapp-backup.timer