From 102a24d6a3343b89bbee4320388cc7a4345a217d Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Thu, 15 Jan 2026 19:27:41 +0100 Subject: [PATCH] woodpecker --- .woodpecker.yml | 28 ++++++ docker-compose.yaml | 26 +++++ docs/PLATFORM.md | 227 ++++++++++++++++++++++++++++++++++++++++++++ server.ts | 2 +- 4 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 .woodpecker.yml create mode 100644 docker-compose.yaml create mode 100644 docs/PLATFORM.md diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..748b31b --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,28 @@ +pipeline: + build: + image: woodpeckerci/plugin-docker + settings: + registry: gitea.infra.mintel.me + repo: gitea.infra.mintel.me/mintel/mb-grid-solutions + username: + from_secret: GITEA_USER + password: + from_secret: GITEA_TOKEN + when: + event: push + branch: main + + deploy: + image: alpine + commands: + - apk add --no-cache openssh + - mkdir -p ~/.ssh + - echo "$ALPHA_SSH_KEY" > ~/.ssh/id_ed25519 + - chmod 600 ~/.ssh/id_ed25519 + - ssh -o StrictHostKeyChecking=no deploy@alpha.mintel.me "mkdir -p /opt/alpha/sites/mb-grid-solutions" + - scp -o StrictHostKeyChecking=no docker-compose.yaml deploy@alpha.mintel.me:/opt/alpha/sites/mb-grid-solutions/docker-compose.yaml + - ssh -o StrictHostKeyChecking=no deploy@alpha.mintel.me "cd /opt/alpha/sites/mb-grid-solutions && docker compose pull && docker compose up -d" + secrets: [ ALPHA_SSH_KEY ] + when: + event: push + branch: main diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..bb523b5 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,26 @@ +services: + app: + build: . + image: gitea.infra.mintel.me/mintel/mb-grid-solutions:latest + restart: always + expose: + - "3000" + labels: + - "traefik.enable=true" + - "traefik.http.routers.mb-grid-solutions.rule=Host(`mb-grid-solutions.com`, `www.mb-grid-solutions.com`)" + - "traefik.http.routers.mb-grid-solutions.entrypoints=websecure" + - "traefik.http.routers.mb-grid-solutions.tls.certresolver=le" + - "traefik.http.services.mb-grid-solutions.loadbalancer.server.port=3000" + healthcheck: + test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:3000/health"] + interval: 5s + timeout: 2s + retries: 10 + deploy: + replicas: 2 + networks: + - alpha + +networks: + alpha: + external: true diff --git a/docs/PLATFORM.md b/docs/PLATFORM.md new file mode 100644 index 0000000..13a400e --- /dev/null +++ b/docs/PLATFORM.md @@ -0,0 +1,227 @@ +# Mintel Alpha Platform — Developer Cheat Sheet + +This platform runs real customer websites on their own domains +(e.g. klz-cables.com, shop.customer.de, example.org). + +You do not manage servers. +You ship Docker containers. +Mintel runs the platform. + +--- + +## Control Plane (Infra) + +These are for developers only (not customers): + +Git +https://git.infra.mintel.me + +CI +https://ci.infra.mintel.me + +Errors (GlitchTip) +https://errors.infra.mintel.me + +Analytics (Umami) +https://analytics.infra.mintel.me + +Uptime +https://status.infra.mintel.me + +Logs +https://logs.infra.mintel.me + +--- + +## Production Platform (Alpha) + +Alpha runs all customer websites and listens on ports 80 and 443 for the entire internet. + +Customer domains point their DNS A records to the Alpha server IP. + +Traefik on Alpha routes domains to the correct containers. + +--- + +## How routing works + +Each web service declares which domains it owns via Traefik labels. + +Example domains: +- klz-cables.com +- www.klz-cables.com + +Traefik routes traffic by Host header. + +--- + +## Directory layout on Alpha + +Each app lives in: + +/opt/alpha/sites/APP_NAME + +This directory contains: +- docker-compose.yml +- .env (optional) +- persistent volumes + +--- + +## Databases + +### Postgres (shared) + +All apps share one Postgres server but use separate databases. + +Connection format: + +postgres://infra:infra@postgres:5432/APP_DB + +Example: + +postgres://infra:infra@postgres:5432/klz_site + +Each app must use its own database. + +--- + +### Redis (shared) + +All apps share one Redis server but use separate DB indexes. + +Connection format: + +redis://redis:6379/N + +Example: + +redis://redis:6379/1 +redis://redis:6379/2 + +Each app must use its own Redis DB number. + +--- + +## Traefik labels (required) + +Every public web service must define these labels: + +traefik.enable=true +traefik.http.routers.app.rule=Host(klz-cables.com,www.klz-cables.com) +traefik.http.routers.app.entrypoints=websecure +traefik.http.routers.app.tls.certresolver=le +traefik.http.services.app.loadbalancer.server.port=YOUR_INTERNAL_PORT + +Traefik automatically provides HTTPS. + +--- + +## Zero-downtime deployments + +All web services must support health checks. + +Your app must expose: + +GET /health +returns HTTP 200 when ready. + +Docker Compose example: + +healthcheck: + test: wget -q -O - http://localhost:3000/health + interval: 5s + timeout: 2s + retries: 10 + +Run multiple replicas: + +deploy: + replicas: 2 + +During deploy: +- New containers start +- They become healthy +- Traefik switches traffic +- Old containers are removed + +No downtime. + +--- + +## Error tracking (GlitchTip) + +Each project gets a DSN, similar to Sentry. + +Example: + +https://PUBLIC_KEY@errors.infra.mintel.me/PROJECT_ID + +Use as SENTRY_DSN in your app. + +All errors appear in GlitchTip. + +--- + +## Analytics (Umami) + +Each site gets a website ID. + +Include this script in your site: + +https://analytics.infra.mintel.me/script.js +data-website-id=YOUR_ID + +Traffic is visible in Umami. + +--- + +## Deployment via Woodpecker + +Woodpecker deploys to Alpha via SSH. + +Target: +deploy@alpha.mintel.me + +Auth: +ALPHA_SSH_KEY is provided as a CI secret. + +--- + +## Woodpecker pipeline example + +Every repo must contain .woodpecker.yml: + +pipeline: + deploy: + image: alpine + commands: + - apk add --no-cache openssh + - mkdir -p ~/.ssh + - echo "$ALPHA_SSH_KEY" > ~/.ssh/id_ed25519 + - chmod 600 ~/.ssh/id_ed25519 + - ssh -o StrictHostKeyChecking=no deploy@alpha.mintel.me "cd /opt/alpha/sites/APP_NAME && docker compose pull && docker compose up -d" + +--- + +## Monitoring + +Errors: GlitchTip +Traffic: Umami +Uptime: Uptime-Kuma +Logs: Dozzle + +Infra monitors all services automatically. + +--- + +## Summary + +You push code. +Woodpecker deploys. +Traefik routes domains. +Postgres and Redis are shared but isolated. +Zero-downtime updates are automatic. +Errors, traffic and uptime are tracked. + +This is a real production platform. \ No newline at end of file diff --git a/server.ts b/server.ts index 64e6f9f..08174d8 100644 --- a/server.ts +++ b/server.ts @@ -92,7 +92,7 @@ ${message} }); // Health check -app.get('/healthz', (req, res) => { +app.get('/health', (req, res) => { res.status(200).send('OK'); });