kennyl777/snippy-api, kennyl777/snippy-frontend, kennyl777/snippy-db, kennyl777/snippy-miniodb MySQL 8 database (schema bootstrap via init.sh) snippy/db api Node/TypeScript Express API snippy/backend frontend Angular SPA snippy/frontend minio / minio-init Optional object storage for asset uploads Chainguard MinIO + snippy/miniodocker-compose.yml docker-compose.prod.example.yml Images Built locally from Dockerfile.dev Pulled from Docker Hub (kennyl777/snippy-*) Frontend ng serve on port 4200 (hot reload) nginx on container port 80 Env file .env stack.env (or Portainer stack env) CI / image publish .github/workflows/ci.yml on PRs .github/workflows/docker-image.yml Network Default Compose network External Docker network named NPM (for Nginx Proxy Manager)Do not use the rootdocker-compose.ymlfor production. It bind-mounts source, runsng serve, and is intended only for local testing.
/try editor, starter templates on /snippet, and public /embed/:shortId player (tabs, editable, theme query params)/public), tag browse (/tags/:tag), profiles, and collection pages without logging in@username links), follows, collections, and forking (forks list + parent attribution)localStorage (including /try after login)/s/:token)Ctrl/Cmd+K)docker compose)check:all)http://localhost:4200 is generally accepted by Auth0 for development.http://192.168.x.x. Put HTTPS in front (self-signed or real cert via Nginx Proxy Manager) and use that hostname in Auth0.AUTH0_DOMAINAUTH0_CLIENT_IDhttp://localhost:4200/home Allowed Logout URLs http://localhost:4200/ Allowed Web Origins http://localhost:4200https://snippy.example.com/home Allowed Logout URLs https://snippy.example.com/ Allowed Web Origins https://snippy.example.comSnippy API).AUTH0_AUDIENCE.
Common default used by this project: http://localhost:3000AUTH0_AUDIENCE in your env file (local and production). The API Identifier is a string identity for tokens; it does not have to be a publicly reachable URL..env Repository root (next to docker-compose.yml) Production (Compose CLI) stack.env Same directory as the prod compose file you run Production (Portainer) Stack environment Set in the Portainer UI (or paste the same keys).env for variable substitution and, in this project, services also mount env_file: ./.env (local) or stack.env (prod example)..env / stack.envMYSQL_ROOT_PASSWORD Yes MySQL root password DB_PASS Yes Password for DB_USER (API connects with this) DB_HOST No db DB_PORT No 3306 (host publish in prod compose uses ${DB_PORT:-3306}) DB_NAME No snippy DB_USER No snippy_api DB_SSL No unset / false — set true only for a remote MySQL that requires TLS (not Docker MySQL on the compose network) AUTH0_DOMAIN Yes (login) Auth0 tenant domain AUTH0_CLIENT_ID Yes (login) SPA Client ID (written into frontend env.js) AUTH0_AUDIENCE No http://localhost:3000 — must match Auth0 API Identifier FRONTEND_URL Strongly recommended http://localhost:4200 — must match the browser origin or CORS will block the API API_PORT No Host port mapped to API 3000 FRONTEND_PORT No (prod) Host port mapped to frontend nginx 8080 (prod example default 4200:8080) ENABLE_MINIO No false — set true only when MinIO is running and reachable as minio:9000 MINIO_* When MinIO enabled Root/app credentials, bucket name/policy, endpointsnippy/frontend/entrypoint.dev.sh writes public/env.js from env vars before ng serve.snippy/frontend/entrypoint.sh writes /usr/share/nginx/html/env.js on container start and selects nginx config with or without MinIO proxying.env.js is regenerated.docker-compose.yml:mysql:8.0 with snippy/db/init.sh mounted into /docker-entrypoint-initdb.dsnippy/backend/Dockerfile.dev, npm run dev (ts-node-dev), source bind-mounted, port 3000snippy/frontend/Dockerfile.dev, ng serve with proxy (proxy.conf.json), port 4200ENABLE_MINIO=true)/api → http://api:3000/content → http://minio:9000 (only useful if MinIO is running).env in the repo root using the example. At minimum set:MYSQL_ROOT_PASSWORDDB_PASSAUTH0_DOMAINAUTH0_CLIENT_IDAUTH0_AUDIENCE (match your Auth0 API Identifier)FRONTEND_URL=http://localhost:4200/api/....minio and minio-init services (and minio_data volume) in docker-compose.yml..env and ENABLE_MINIO=true.docker compose up --build.package.json wraps backend and frontend scripts so you can format, regenerate the OpenAPI client, and run the same checks as .github/workflows/ci.yml before you open a PR.npm ci in each folder):generate:api when routes, DTOs, or openapi-definition.ts changed. Commit both openapi.json files and snippy/frontend/src/app/api/generated/.check:all stops on the first failure. It runs, in CI order:check:audit npm audit --audit-level=high in backend and frontend Format check:format Prettier check (does not write) Types check:types tsc --noEmit (backend) and tsc -p tsconfig.app.json (frontend) OpenAPI check:openapi Regenerates spec + client, then git diff --exit-code Build check:build Backend tsc build and frontend production ng build Tests check:test Backend Vitest (npm test)npm run dev:backend / dev:frontend Run API or Angular outside Docker npm run build:backend / build:frontend Build one package npm run test:all Backend Vitest and frontend Karma (not in CI; Karma may need a browser) npm run docker:compose:up docker compose build && up npm run docker:compose:clear Wipe volumes, rebuild, and startkennyl777/snippy-*. Images are built by the manual GitHub Actions workflow .github/workflows/docker-image.yml (workflow_dispatch), which pushes both version tags (from package.json) and :latest.kennyl777/snippy-api:latest API (compiled Node) kennyl777/snippy-frontend:latest Angular SPA served by nginx kennyl777/snippy-db:latest MySQL 8 + init script kennyl777/snippy-minio:latest One-shot MinIO bucket/user bootstrapdocker-compose.prod.example.yml as your starting point. That file:stack.envNPMminio-init${FRONTEND_PORT:-4200} → container 8080FRONTEND_URL must be the exact public origin users type into the browser (scheme + host, no path), or CORS will fail.NPM network before starting the stack (see below), even if you are not using Nginx Proxy Manager yet—or edit the compose file to use a different network.stack.env next to that compose file with production values. Example differences from local:snippy-frontend container on port 8080 (or whatever host port you published). See Nginx Proxy Manager setup.docker-compose.prod.example.yml (or upload the file).stack.env under the stack Environment variables UI.
If Portainer still expects a file named stack.env because of env_file: stack.env in the compose, either:stack.env on the host path Portainer uses for that stack, orenv_file entries to match how you inject env in Portainer.snippy-frontend:8080 on the NPM network (container-to-container), or to the published host port if you prefer.8080 4200 (FRONTEND_PORT) api 3000 3000 (API_PORT) db 3306 3306 (DB_PORT) minio API 9000 32570 minio console 9001 32571/api/ to http://api:3000 on the Docker network.mysql-data volume.init.sh runs only on first initialization of an empty data directory.DB_PASS later does not automatically update an already-created MySQL user—plan passwords before first boot, or reset the volume (docker compose ... down -v) knowing that deletes data.NPM networkexternal: true.http://<docker-host>:81NPM network.snippy.example.comhttpsnippy-frontend (container name)
or the Docker host IP if forwarding to a published port8080 (container) or your published FRONTEND_PORTFRONTEND_URL use https://snippy.example.com.:latest (or pin specific version tags from Docker Hub / package.json versions for more control).snippy/backend/package.jsonsnippy/frontend/package.jsonlatest (and version when available) by the workflowAUTH0_DOMAIN / AUTH0_CLIENT_ID, or callback URL mismatch Fix .env / stack.env, restart frontend, verify Auth0 URIs exactly match the browser URL Auth0 “secure origin” / callback failures on LAN IP Using http://192.168.x.x Put HTTPS in front (NPM) and use a hostname API calls fail with CORS errors FRONTEND_URL ≠ browser origin Set FRONTEND_URL to exact origin (https://snippy.example.com), restart api Frontend loads but API 502/404 API not healthy, or nginx/proxy misconfigured docker compose logs api; confirm frontend can reach api:3000 on the Docker network API crashes on boot Missing DB_PASS or AUTH0_DOMAIN Required by API config validation — set them and recreate the API container DB init / auth failures Wrong MYSQL_ROOT_PASSWORD / DB_PASS, or volume from older credentials Align env with existing volume, or down -v for a clean DB (destructive) network NPM declared as external, but could not be found Network not created docker network create NPM MinIO / assets unavailable ENABLE_MINIO false, MinIO not running, or MinIO process exited Give the minio service restart: unless-stopped (Portainer). Healthcheck looks for port 9000 in /proc/net/tcp (works without curl/bash/wget). After a connection failure the API latches MinIO off until API restart; the SPA probes GET /api/v1/health and latches Assets / Profile Image / snapshot-on-save until you restart the stack and reload minio/mc:latest / minio/minio:latest pull denied MinIO removed community images from Docker Hub Use cgr.dev/chainguard/minio and cgr.dev/chainguard/minio-client (already wired in compose + snippy/minio/Dockerfile) Env changes ignored in browser Stale env.js Restart frontend container and hard-refresh the browserPUT /users + editorPreferences documentation/db.md Schema (including users.editor_preferences) documentation/openapi.json Exported OpenAPI snapshot. From the repo root: npm run generate:api (dumps spec + generates the SPA client) documentation/frontend-test-plan.md Manual QA checklist/privacy/termsPosted Sep 27, 2026
Developed an open-source CodePen-style app for HTML, CSS, JS snippets with Docker support.
0
3