From 3b12831ebea1f41c880b03c2ba07c8f419c395ea Mon Sep 17 00:00:00 2001 From: Ochenstarik Date: Thu, 10 Sep 2026 23:29:29 +0700 Subject: [PATCH] ci: add portable deployment and verification pipeline --- .dockerignore | 6 ++++++ .env.example | 19 +++++++++++++++++++ .forgejo/workflows/ci.yml | 16 ++++++++++++++++ Dockerfile | 22 ++++++++++++++++++++++ compose.yaml | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .forgejo/workflows/ci.yml create mode 100644 Dockerfile create mode 100644 compose.yaml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9839cb3 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +.git +node_modules +dist +coverage +.env +backups diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..dac5c2c --- /dev/null +++ b/.env.example @@ -0,0 +1,19 @@ +NODE_ENV=development +PORT=8080 +LOG_LEVEL=info +STAFF_RUNTIME_MODE=standalone +DATABASE_URL=postgres://krona_staff:krona_staff@postgres:5432/krona_staff +REDIS_URL=redis://redis:6379 +PLATFORM_GATEWAY_URL=http://host.docker.internal:3000 +PLATFORM_JWT_ISSUER=https://platform.example.invalid +PLATFORM_JWT_AUDIENCE=krona-staff +PLATFORM_JWKS_URL=https://platform.example.invalid/.well-known/jwks.json +STANDALONE_TENANT_ID=01J00000000000000000000000 +STANDALONE_ACTOR_ID=01J00000000000000000000001 +OBJECT_STORAGE_DRIVER=s3 +S3_ENDPOINT=http://minio:9000 +S3_REGION=us-east-1 +S3_BUCKET=krona-staff +S3_ACCESS_KEY_ID=change-me +S3_SECRET_ACCESS_KEY=change-me +BACKUP_ENCRYPTION_RECIPIENT=age1replace-with-public-recipient diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..08b72e9 --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,16 @@ +name: ci +on: + push: + branches: [main, codex/bootstrap-platform-foundation] + pull_request: +jobs: + verify: + runs-on: docker + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: { node-version: 22, cache: npm } + - run: npm ci + - run: npm run check + - run: npm audit --audit-level=high + - run: docker build -t krona-staff:${{ forgejo.sha }} . diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e306168 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +# syntax=docker/dockerfile:1.7 +FROM node:22-alpine AS build +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm ci +COPY tsconfig.json tsconfig.build.json eslint.config.js ./ +COPY src ./src +COPY scripts ./scripts +COPY migrations ./migrations +RUN npm run build + +FROM node:22-alpine AS runtime +ENV NODE_ENV=production +WORKDIR /app +RUN addgroup -S app && adduser -S -G app app +COPY package.json package-lock.json ./ +RUN npm ci --omit=dev && npm cache clean --force +COPY --from=build /app/dist ./dist +USER app +EXPOSE 8080 +HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD wget -q -O - http://127.0.0.1:8080/live || exit 1 +CMD ["node", "dist/server.js"] diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..a826dd1 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,35 @@ +services: + app: + build: . + env_file: .env + ports: ["8080:8080"] + depends_on: + postgres: { condition: service_healthy } + redis: { condition: service_healthy } + restart: unless-stopped + read_only: true + tmpfs: [/tmp] + security_opt: ["no-new-privileges:true"] + migrate: + build: { context: ., target: build } + env_file: .env + command: ["node", "scripts/migrate.mjs", "up"] + depends_on: + postgres: { condition: service_healthy } + profiles: ["tools"] + postgres: + image: postgres:17-alpine + environment: + POSTGRES_DB: krona_staff + POSTGRES_USER: krona_staff + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-local-development-only} + volumes: ["postgres-data:/var/lib/postgresql/data"] + healthcheck: { test: ["CMD-SHELL", "pg_isready -U krona_staff -d krona_staff"], interval: 5s, timeout: 3s, retries: 20 } + redis: + image: redis:7-alpine + command: ["redis-server", "--appendonly", "yes"] + volumes: ["redis-data:/data"] + healthcheck: { test: ["CMD", "redis-cli", "ping"], interval: 5s, timeout: 3s, retries: 20 } +volumes: + postgres-data: + redis-data: