because I got bored of customising my CV for every job
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore(CVG-29): strip vendoring from Dockerfiles, remove Caddy

+46 -259
-60
.docker/client.Dockerfile
··· 1 - FROM node:24-bookworm-slim AS development 2 - 3 - RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/* 4 - RUN corepack enable && corepack prepare pnpm@latest --activate 5 - 6 - WORKDIR /app 7 - 8 - # Layer 1: workspace config + lockfile 9 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 10 - 11 - # Layer 2: package.json manifests only 12 - COPY .docker/.manifests/ /tmp/manifests/ 13 - COPY .docker/restore-manifests.sh /tmp/ 14 - RUN sh /tmp/restore-manifests.sh /tmp/manifests 15 - 16 - # Layer 3: install (skip native addon builds — canvas is server-only) 17 - RUN pnpm install --frozen-lockfile --ignore-scripts 18 - 19 - # Layer 4: source code 20 - COPY packages/ ./packages/ 21 - COPY apps/client/ ./apps/client/ 22 - 23 - EXPOSE 5173 24 - 25 - WORKDIR /app/apps/client 26 - CMD ["pnpm", "dev"] 27 - 28 - # ---- Production build ---- 29 - FROM node:24-bookworm-slim AS builder 30 - 31 - RUN corepack enable && corepack prepare pnpm@latest --activate 32 - 33 - WORKDIR /app 34 - 35 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 36 - COPY .docker/.manifests/ /tmp/manifests/ 37 - COPY .docker/restore-manifests.sh /tmp/ 38 - RUN sh /tmp/restore-manifests.sh /tmp/manifests 39 - RUN pnpm install --frozen-lockfile --ignore-scripts 40 - 41 - COPY packages/ ./packages/ 42 - COPY apps/client/ ./apps/client/ 43 - 44 - ARG VITE_SERVER_URL 45 - ARG VITE_DOCS_URL 46 - ENV VITE_SERVER_URL=${VITE_SERVER_URL} 47 - ENV VITE_DOCS_URL=${VITE_DOCS_URL} 48 - 49 - WORKDIR /app/apps/client 50 - RUN pnpm exec vite build 51 - 52 - # ---- Production serve ---- 53 - FROM nginx:alpine AS production 54 - 55 - COPY --from=builder /app/apps/client/dist /usr/share/nginx/html 56 - COPY apps/client/nginx.conf /etc/nginx/conf.d/default.conf 57 - 58 - EXPOSE 80 59 - 60 - CMD ["nginx", "-g", "daemon off;"]
-64
.docker/patch-vendor-links.sh
··· 1 - #!/bin/sh 2 - # Patches link: paths in package.json to point to vendored copies at 3 - # $ROOT/vendor/ so pnpm install can resolve them with --frozen-lockfile. 4 - # 5 - # Also creates a /riotbyte/project-q/packages/ directory tree that 6 - # mirrors the layout pnpm's lockfile expects (relative link: targets 7 - # resolve to /riotbyte/... inside Docker because the workspace root 8 - # is at /app which is only 1 level deep). 9 - # 10 - # Usage: patch-vendor-links.sh [workspace-root] 11 - 12 - set -e 13 - 14 - ROOT="${1:-.}" 15 - 16 - # Step 1: Patch package.json specifiers (link:host-path → link:$ROOT/vendor/*) 17 - # pnpm validates specifiers match package.json during --frozen-lockfile 18 - find "$ROOT" -name 'package.json' -not -path '*/node_modules/*' | while read -r f; do 19 - if grep -q '"link:.*project-q\|"link:.*nest-service-locator' "$f" 2>/dev/null; then 20 - sed -i \ 21 - -e "s|\"link:[^\"]*project-q/packages/core\"|\"link:$ROOT/vendor/project-q-core\"|g" \ 22 - -e "s|\"link:[^\"]*project-q/packages/framework/nest\"|\"link:$ROOT/vendor/project-q-nestjs\"|g" \ 23 - -e "s|\"link:[^\"]*project-q/packages/transport/prisma\"|\"link:$ROOT/vendor/project-q-prisma\"|g" \ 24 - -e "s|\"link:[^\"]*nest-service-locator\"|\"link:$ROOT/vendor/nest-service-locator\"|g" \ 25 - "$f" 26 - echo "Patched $f" 27 - fi 28 - done 29 - 30 - # Step 2: Patch lockfile specifiers to match the package.json changes 31 - # Only patch absolute specifier lines (link:/...), leave relative 32 - # version lines untouched — they resolve via mount points below. 33 - LOCKFILE="$ROOT/pnpm-lock.yaml" 34 - if [ -f "$LOCKFILE" ] && grep -q 'project-q\|nest-service-locator' "$LOCKFILE" 2>/dev/null; then 35 - sed -i \ 36 - -e "s|link:/[^ ]*project-q/packages/core|link:$ROOT/vendor/project-q-core|g" \ 37 - -e "s|link:/[^ ]*project-q/packages/framework/nest|link:$ROOT/vendor/project-q-nestjs|g" \ 38 - -e "s|link:/[^ ]*project-q/packages/transport/prisma|link:$ROOT/vendor/project-q-prisma|g" \ 39 - -e "s|link:/[^ ]*nest-service-locator|link:$ROOT/vendor/nest-service-locator|g" \ 40 - "$LOCKFILE" 41 - echo "Patched $LOCKFILE" 42 - fi 43 - 44 - # Step 3: Create mount points so pnpm's relative symlinks resolve correctly. 45 - # Inside Docker, relative link: paths from the lockfile resolve to 46 - # /riotbyte/project-q/packages/* (because the workspace is at /app). 47 - # We create symlinks there pointing to the vendored copies inside the 48 - # workspace tree (at $ROOT/vendor/). 49 - mkdir -p /riotbyte/project-q/packages/framework /riotbyte/project-q/packages/transport /riotbyte 50 - ln -sfn "$ROOT/vendor/project-q-core" /riotbyte/project-q/packages/core 51 - ln -sfn "$ROOT/vendor/project-q-nestjs" /riotbyte/project-q/packages/framework/nest 52 - ln -sfn "$ROOT/vendor/project-q-prisma" /riotbyte/project-q/packages/transport/prisma 53 - ln -sfn "$ROOT/vendor/nest-service-locator" /riotbyte/nest-service-locator 54 - echo "Created mount points at /riotbyte/" 55 - 56 - # Step 4: Create root-level node_modules symlinks so vendored packages 57 - # can resolve each other (e.g. transport-postgres depends on core). 58 - # pnpm only creates per-workspace symlinks for link: deps, not at root. 59 - mkdir -p "$ROOT/node_modules/@riotbyte" 60 - ln -sfn "$ROOT/vendor/project-q-core" "$ROOT/node_modules/@riotbyte/project-q-core" 61 - ln -sfn "$ROOT/vendor/project-q-nestjs" "$ROOT/node_modules/@riotbyte/project-q-nestjs" 62 - ln -sfn "$ROOT/vendor/project-q-prisma" "$ROOT/node_modules/@riotbyte/project-q-prisma" 63 - ln -sfn "$ROOT/vendor/nest-service-locator" "$ROOT/node_modules/@riotbyte/nest-service-locator" 64 - echo "Created root node_modules symlinks for vendored packages"
+17 -41
.docker/server.Dockerfile
··· 19 19 COPY .docker/restore-manifests.sh /tmp/ 20 20 RUN sh /tmp/restore-manifests.sh /tmp/manifests 21 21 22 - # Layer 2b: vendor project-q packages (from additional build context) 23 - COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 24 - COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 25 - COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 26 - COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 27 - COPY --from=project-q packages/transport/prisma/package.json ./vendor/project-q-prisma/package.json 28 - COPY --from=project-q packages/transport/prisma/dist/ ./vendor/project-q-prisma/dist/ 29 - COPY --from=nest-service-locator package.json ./vendor/nest-service-locator/package.json 30 - COPY --from=nest-service-locator dist/src/ ./vendor/nest-service-locator/dist/src/ 22 + # GHCR npm auth for @riotbyte-com packages 23 + ARG GITHUB_TOKEN 24 + COPY .npmrc .npmrc 25 + RUN echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc 31 26 32 - # Patch link: → file: for project-q packages 33 - COPY .docker/patch-vendor-links.sh /tmp/ 34 - RUN sh /tmp/patch-vendor-links.sh /app 35 - 36 - # Layer 3: install (lockfile was patched above to match vendored paths) 37 - RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile 27 + # Layer 3: install 28 + RUN pnpm install --frozen-lockfile 38 29 39 30 # Layer 4: source code (changes frequently) 40 31 COPY packages/ ./packages/ 41 32 COPY apps/server/ ./apps/server/ 42 - 43 - # Patch server package.json too (COPY overwrote the patched version) 44 - RUN sh /tmp/patch-vendor-links.sh /app 45 33 46 34 # Generate Prisma client 47 35 WORKDIR /app/apps/server ··· 68 56 COPY .docker/restore-manifests.sh /tmp/ 69 57 RUN sh /tmp/restore-manifests.sh /tmp/manifests 70 58 71 - COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 72 - COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 73 - COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 74 - COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 75 - COPY --from=project-q packages/transport/prisma/package.json ./vendor/project-q-prisma/package.json 76 - COPY --from=project-q packages/transport/prisma/dist/ ./vendor/project-q-prisma/dist/ 77 - 78 - COPY .docker/patch-vendor-links.sh /tmp/ 79 - RUN sh /tmp/patch-vendor-links.sh /app 59 + ARG GITHUB_TOKEN 60 + COPY .npmrc .npmrc 61 + RUN echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc 80 62 81 - RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile 63 + RUN pnpm install --frozen-lockfile 82 64 83 65 COPY packages/ ./packages/ 84 66 COPY apps/server/ ./apps/server/ 85 - RUN sh /tmp/patch-vendor-links.sh /app 86 67 87 68 WORKDIR /app/apps/server 88 69 RUN pnpm exec prisma generate ··· 106 87 COPY .docker/restore-manifests.sh /tmp/ 107 88 RUN sh /tmp/restore-manifests.sh /tmp/manifests 108 89 109 - COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 110 - COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 111 - COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 112 - COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 113 - COPY --from=project-q packages/transport/prisma/package.json ./vendor/project-q-prisma/package.json 114 - COPY --from=project-q packages/transport/prisma/dist/ ./vendor/project-q-prisma/dist/ 115 - COPY --from=nest-service-locator package.json ./vendor/nest-service-locator/package.json 116 - COPY --from=nest-service-locator dist/src/ ./vendor/nest-service-locator/dist/src/ 90 + ARG GITHUB_TOKEN 91 + COPY .npmrc .npmrc 92 + RUN echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc 117 93 118 - COPY .docker/patch-vendor-links.sh /tmp/ 119 - RUN sh /tmp/patch-vendor-links.sh /app 120 - 121 - RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile --prod 94 + RUN pnpm install --frozen-lockfile --prod 122 95 123 96 # Copy Prisma schema + generated client 124 97 COPY apps/server/prisma/ ./apps/server/prisma/ ··· 127 100 128 101 # Copy bundled output (single file, @cv/* packages inlined) 129 102 COPY --from=builder /app/apps/server/dist/ ./apps/server/dist/ 103 + 104 + # Remove auth token from final image 105 + RUN sed -i '/_authToken/d' .npmrc 130 106 131 107 ENV NODE_ENV=production 132 108 EXPOSE 3000
+19 -46
.docker/worker.Dockerfile
··· 13 13 COPY .docker/restore-manifests.sh /tmp/ 14 14 RUN sh /tmp/restore-manifests.sh /tmp/manifests 15 15 16 - # Layer 2b: vendor project-q packages (inside workspace tree so Node 17 - # module resolution walks up to /app/node_modules) 18 - COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 19 - COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 20 - COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 21 - COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 22 - COPY --from=project-q packages/transport/prisma/package.json ./vendor/project-q-prisma/package.json 23 - COPY --from=project-q packages/transport/prisma/dist/ ./vendor/project-q-prisma/dist/ 24 - COPY --from=nest-service-locator package.json ./vendor/nest-service-locator/package.json 25 - COPY --from=nest-service-locator dist/src/ ./vendor/nest-service-locator/dist/src/ 16 + # GHCR npm auth for @riotbyte-com packages 17 + ARG GITHUB_TOKEN 18 + COPY .npmrc .npmrc 19 + RUN echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc 26 20 27 - # Patch link: specifiers + create mount points for lockfile relative paths 28 - COPY .docker/patch-vendor-links.sh /tmp/ 29 - RUN sh /tmp/patch-vendor-links.sh /app 30 - 31 - # Layer 3: install (lockfile was patched above to match vendored paths) 32 - # shamefully-hoist makes all deps available at /app/node_modules/ so 33 - # vendored project-q packages (linked via link: protocol) can resolve 34 - # their transitive deps (uuid, zod, pg) through Node's upward walk. 35 - RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile 21 + # Layer 3: install 22 + RUN pnpm install --frozen-lockfile 36 23 37 24 # Layer 4: source code 38 25 COPY packages/tsconfig/ ./packages/tsconfig/ 39 26 COPY packages/system/ ./packages/system/ 27 + COPY packages/file-storage/ ./packages/file-storage/ 40 28 COPY apps/server/prisma/ ./apps/server/prisma/ 41 29 COPY apps/worker/ ./apps/worker/ 42 - RUN sh /tmp/patch-vendor-links.sh /app 43 30 44 31 # Generate Prisma client (@cv/system depends on @prisma/client) 45 32 RUN cd apps/server && pnpm exec prisma generate ··· 63 50 COPY .docker/restore-manifests.sh /tmp/ 64 51 RUN sh /tmp/restore-manifests.sh /tmp/manifests 65 52 66 - COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 67 - COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 68 - COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 69 - COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 70 - COPY --from=project-q packages/transport/prisma/package.json ./vendor/project-q-prisma/package.json 71 - COPY --from=project-q packages/transport/prisma/dist/ ./vendor/project-q-prisma/dist/ 53 + ARG GITHUB_TOKEN 54 + COPY .npmrc .npmrc 55 + RUN echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc 72 56 73 - COPY .docker/patch-vendor-links.sh /tmp/ 74 - RUN sh /tmp/patch-vendor-links.sh /app 75 - 76 - # shamefully-hoist makes all deps available at /app/node_modules/ so 77 - # vendored project-q packages (linked via link: protocol) can resolve 78 - # their transitive deps (uuid, zod, pg) through Node's upward walk. 79 - RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile 57 + RUN pnpm install --frozen-lockfile 80 58 81 59 COPY packages/tsconfig/ ./packages/tsconfig/ 82 60 COPY packages/system/ ./packages/system/ 61 + COPY packages/file-storage/ ./packages/file-storage/ 83 62 COPY apps/server/prisma/ ./apps/server/prisma/ 84 63 COPY apps/worker/ ./apps/worker/ 85 - RUN sh /tmp/patch-vendor-links.sh /app 86 64 87 65 RUN cd apps/server && pnpm exec prisma generate 88 66 ··· 101 79 COPY .docker/restore-manifests.sh /tmp/ 102 80 RUN sh /tmp/restore-manifests.sh /tmp/manifests 103 81 104 - COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 105 - COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 106 - COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 107 - COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 108 - COPY --from=project-q packages/transport/prisma/package.json ./vendor/project-q-prisma/package.json 109 - COPY --from=project-q packages/transport/prisma/dist/ ./vendor/project-q-prisma/dist/ 110 - COPY --from=nest-service-locator package.json ./vendor/nest-service-locator/package.json 111 - COPY --from=nest-service-locator dist/src/ ./vendor/nest-service-locator/dist/src/ 112 - 113 - COPY .docker/patch-vendor-links.sh /tmp/ 114 - RUN sh /tmp/patch-vendor-links.sh /app 82 + ARG GITHUB_TOKEN 83 + COPY .npmrc .npmrc 84 + RUN echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc 115 85 116 - RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile --prod 86 + RUN pnpm install --frozen-lockfile --prod 117 87 118 88 # Install Chromium + system deps via Playwright 119 89 RUN cd apps/worker && pnpm exec playwright install --with-deps chromium 120 90 121 91 # Copy compiled output 122 92 COPY --from=builder /app/apps/worker/dist/ ./apps/worker/dist/ 93 + 94 + # Remove auth token from final image 95 + RUN sed -i '/_authToken/d' .npmrc 123 96 124 97 ENV NODE_ENV=production 125 98
+10 -48
docker-compose.prod.yml
··· 1 1 services: 2 - caddy: 3 - image: caddy:2-alpine 4 - environment: 5 - DOMAIN: ${DOMAIN} 6 - BASIC_AUTH_USER: ${BASIC_AUTH_USER:-admin} 7 - BASIC_AUTH_HASH: ${BASIC_AUTH_HASH} 8 - ports: 9 - - "80:80" 10 - - "443:443" 11 - volumes: 12 - - ./ci/Caddyfile:/etc/caddy/Caddyfile:ro 13 - - caddy-data:/data 14 - - caddy-config:/config 15 - depends_on: 16 - server: 17 - condition: service_healthy 18 - client: 19 - condition: service_healthy 20 - restart: unless-stopped 21 - 22 2 db: 23 3 image: postgres:16-alpine 24 4 environment: ··· 39 19 context: . 40 20 dockerfile: .docker/server.Dockerfile 41 21 target: production 42 - additional_contexts: 43 - project-q: ${PROJECT_Q_PATH} 44 - nest-service-locator: ${NEST_SERVICE_LOCATOR_PATH} 22 + args: 23 + GITHUB_TOKEN: ${GITHUB_TOKEN} 45 24 environment: 46 25 PORT: "3000" 47 26 NODE_ENV: production ··· 53 32 RESEND_API_KEY: ${RESEND_API_KEY:-} 54 33 EMAIL_FROM_ADDRESS: ${EMAIL_FROM_ADDRESS:-} 55 34 EMAIL_FROM_NAME: ${EMAIL_FROM_NAME:-CV Generator} 56 - CLIENT_URL: ${PUBLIC_URL} 57 - ALLOWED_ORIGINS: ${PUBLIC_URL} 35 + CLIENT_URL: ${CLIENT_URL:-http://localhost:5173} 36 + ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-http://localhost:5173} 58 37 AI_PROVIDER: ${AI_PROVIDER:-anthropic} 59 38 AI_TEMPERATURE: ${AI_TEMPERATURE:-0.1} 60 39 AI_MAX_TOKENS: ${AI_MAX_TOKENS:-8192} ··· 63 42 ANTHROPIC_MODEL: ${ANTHROPIC_MODEL:-claude-sonnet-4-5-20250929} 64 43 OPENAI_API_KEY: ${OPENAI_API_KEY:-} 65 44 OPENAI_MODEL: ${OPENAI_MODEL:-gpt-4o-mini} 45 + FILE_STORAGE_DRIVER: ${FILE_STORAGE_DRIVER:-disk} 66 46 PDF_OUTPUT_DIR: /app/pdf-output 67 47 depends_on: 68 48 db: ··· 77 57 start_period: 30s 78 58 restart: unless-stopped 79 59 80 - client: 81 - build: 82 - context: . 83 - dockerfile: .docker/client.Dockerfile 84 - target: production 85 - args: 86 - VITE_SERVER_URL: ${PUBLIC_URL} 87 - VITE_DOCS_URL: https://docs.${DOMAIN} 88 - healthcheck: 89 - test: ["CMD", "curl", "-f", "http://localhost:80"] 90 - interval: 15s 91 - timeout: 5s 92 - retries: 3 93 - start_period: 5s 94 - restart: unless-stopped 95 - 96 60 worker: 97 61 build: 98 62 context: . 99 63 dockerfile: .docker/worker.Dockerfile 100 64 target: production 101 - additional_contexts: 102 - project-q: ${PROJECT_Q_PATH} 103 - nest-service-locator: ${NEST_SERVICE_LOCATOR_PATH} 65 + args: 66 + GITHUB_TOKEN: ${GITHUB_TOKEN} 104 67 environment: 105 68 DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB} 106 69 QUEUE_SCHEMA: ${QUEUE_SCHEMA:-queue} 107 70 QUEUE_NAME: ${QUEUE_NAME:-default} 108 71 POLL_INTERVAL_MS: ${POLL_INTERVAL_MS:-2000} 72 + FILE_STORAGE_DRIVER: ${FILE_STORAGE_DRIVER:-disk} 109 73 PDF_OUTPUT_DIR: /app/pdf-output 110 74 PDF_TIMEOUT_MS: ${PDF_TIMEOUT_MS:-30000} 111 75 HEARTBEAT_FILE_PATH: /tmp/worker-heartbeat ··· 136 100 dockerfile: .docker/docs.Dockerfile 137 101 target: production 138 102 args: 139 - VITE_CLIENT_URL: ${PUBLIC_URL} 140 - VITE_SERVER_URL: ${PUBLIC_URL} 103 + VITE_CLIENT_URL: ${CLIENT_URL:-http://localhost:5173} 104 + VITE_SERVER_URL: ${CLIENT_URL:-http://localhost:5173} 141 105 healthcheck: 142 106 test: ["CMD", "curl", "-f", "http://localhost:80"] 143 107 interval: 15s ··· 149 113 volumes: 150 114 db-data: 151 115 worker-output: 152 - caddy-data: 153 - caddy-config: