Daily Quote app
Go to file
Daily Quote Builder 4af9654002
All checks were successful
CI / build (push) Successful in 22s
Document Gitea Actions runner behavior in README
2026-07-20 17:05:22 +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 CI: quiet runner logging back to info 2026-07-20 17:00:59 +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 Document Gitea Actions runner behavior in README 2026-07-20 17:05:22 +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. Verified working end-to-end (checkout → build → syntax check, all green), but the runner has occasionally been slow to pick up a freshly-pushed task on this VM; a docker restart quoteapp-gitea-runner reliably kicks it back into gear if a run seems stuck in "queued".
  • 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