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.

build(docker): relocate Dockerfiles to .docker/ and add manifest staging scripts

+524 -189
+55
.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 + WORKDIR /app/apps/client 45 + RUN pnpm build 46 + 47 + # ---- Production serve ---- 48 + FROM nginx:alpine AS production 49 + 50 + COPY --from=builder /app/apps/client/dist /usr/share/nginx/html 51 + COPY apps/client/nginx.conf /etc/nginx/conf.d/default.conf 52 + 53 + EXPOSE 80 54 + 55 + CMD ["nginx", "-g", "daemon off;"]
+20
.docker/copy-manifests.sh
··· 1 + #!/bin/sh 2 + # Copies all workspace package.json files into a staging directory 3 + # with encoded filenames (path separators → __) so Docker COPY can 4 + # grab them in one layer. The Dockerfile reverses the encoding. 5 + # 6 + # Usage: .docker/copy-manifests.sh <output-dir> 7 + 8 + set -e 9 + 10 + OUT="${1:-.docker/.manifests}" 11 + rm -rf "$OUT" 12 + mkdir -p "$OUT" 13 + 14 + for f in apps/*/package.json packages/*/package.json; do 15 + [ -f "$f" ] || continue 16 + encoded=$(echo "$f" | sed 's|/|__|g') 17 + cp "$f" "$OUT/$encoded" 18 + done 19 + 20 + echo "Copied $(ls "$OUT" | wc -l | tr -d ' ') manifests to $OUT"
+55
.docker/docs.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/docs/ ./apps/docs/ 22 + 23 + EXPOSE 3001 24 + 25 + WORKDIR /app/apps/docs 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/docs/ ./apps/docs/ 43 + 44 + WORKDIR /app/apps/docs 45 + RUN pnpm build 46 + 47 + # ---- Production serve ---- 48 + FROM nginx:alpine AS production 49 + 50 + COPY --from=builder /app/apps/docs/dist /usr/share/nginx/html 51 + COPY apps/docs/nginx.conf /etc/nginx/conf.d/default.conf 52 + 53 + EXPOSE 80 54 + 55 + CMD ["nginx", "-g", "daemon off;"]
+60
.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' "$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/postgres\"|\"link:$ROOT/vendor/project-q-transport-postgres\"|g" \ 24 + "$f" 25 + echo "Patched $f" 26 + fi 27 + done 28 + 29 + # Step 2: Patch lockfile specifiers to match the package.json changes 30 + # Only patch absolute specifier lines (link:/...), leave relative 31 + # version lines untouched — they resolve via mount points below. 32 + LOCKFILE="$ROOT/pnpm-lock.yaml" 33 + if [ -f "$LOCKFILE" ] && grep -q 'project-q' "$LOCKFILE" 2>/dev/null; then 34 + sed -i \ 35 + -e "s|link:/[^ ]*project-q/packages/core|link:$ROOT/vendor/project-q-core|g" \ 36 + -e "s|link:/[^ ]*project-q/packages/framework/nest|link:$ROOT/vendor/project-q-nestjs|g" \ 37 + -e "s|link:/[^ ]*project-q/packages/transport/postgres|link:$ROOT/vendor/project-q-transport-postgres|g" \ 38 + "$LOCKFILE" 39 + echo "Patched $LOCKFILE" 40 + fi 41 + 42 + # Step 3: Create mount points so pnpm's relative symlinks resolve correctly. 43 + # Inside Docker, relative link: paths from the lockfile resolve to 44 + # /riotbyte/project-q/packages/* (because the workspace is at /app). 45 + # We create symlinks there pointing to the vendored copies inside the 46 + # workspace tree (at $ROOT/vendor/). 47 + mkdir -p /riotbyte/project-q/packages/framework /riotbyte/project-q/packages/transport 48 + ln -sfn "$ROOT/vendor/project-q-core" /riotbyte/project-q/packages/core 49 + ln -sfn "$ROOT/vendor/project-q-nestjs" /riotbyte/project-q/packages/framework/nest 50 + ln -sfn "$ROOT/vendor/project-q-transport-postgres" /riotbyte/project-q/packages/transport/postgres 51 + echo "Created mount points at /riotbyte/project-q/packages/" 52 + 53 + # Step 4: Create root-level node_modules symlinks so vendored packages 54 + # can resolve each other (e.g. transport-postgres depends on core). 55 + # pnpm only creates per-workspace symlinks for link: deps, not at root. 56 + mkdir -p "$ROOT/node_modules/@riotbyte" 57 + ln -sfn "$ROOT/vendor/project-q-core" "$ROOT/node_modules/@riotbyte/project-q-core" 58 + ln -sfn "$ROOT/vendor/project-q-nestjs" "$ROOT/node_modules/@riotbyte/project-q-nestjs" 59 + ln -sfn "$ROOT/vendor/project-q-transport-postgres" "$ROOT/node_modules/@riotbyte/project-q-transport-postgres" 60 + echo "Created root node_modules symlinks for project-q"
+16
.docker/restore-manifests.sh
··· 1 + #!/bin/sh 2 + # Restores encoded package.json files back to their original paths. 3 + # Reverses the encoding from copy-manifests.sh (__ → /). 4 + # 5 + # Usage: restore-manifests.sh <manifests-dir> 6 + 7 + set -e 8 + 9 + DIR="${1:-/tmp/manifests}" 10 + 11 + for f in "$DIR"/*; do 12 + [ -f "$f" ] || continue 13 + original=$(basename "$f" | sed 's|__|/|g') 14 + mkdir -p "$(dirname "$original")" 15 + mv "$f" "$original" 16 + done
+133
.docker/server.Dockerfile
··· 1 + FROM node:24-bookworm-slim AS development 2 + 3 + # canvas (node-canvas) native build deps 4 + RUN apt-get update && apt-get install -y --no-install-recommends \ 5 + curl openssl \ 6 + build-essential python3 pkg-config \ 7 + libpixman-1-dev libcairo2-dev libpango1.0-dev \ 8 + libjpeg-dev libgif-dev librsvg2-dev \ 9 + && rm -rf /var/lib/apt/lists/* 10 + RUN corepack enable && corepack prepare pnpm@latest --activate 11 + 12 + WORKDIR /app 13 + 14 + # Layer 1: workspace config + lockfile (rarely changes) 15 + COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 16 + 17 + # Layer 2: package.json manifests only (changes when deps change) 18 + COPY .docker/.manifests/ /tmp/manifests/ 19 + COPY .docker/restore-manifests.sh /tmp/ 20 + RUN sh /tmp/restore-manifests.sh /tmp/manifests 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/postgres/package.json ./vendor/project-q-transport-postgres/package.json 28 + COPY --from=project-q packages/transport/postgres/dist/ ./vendor/project-q-transport-postgres/dist/ 29 + 30 + # Patch link: → file: for project-q packages 31 + COPY .docker/patch-vendor-links.sh /tmp/ 32 + RUN sh /tmp/patch-vendor-links.sh /app 33 + 34 + # Layer 3: install (lockfile was patched above to match vendored paths) 35 + RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile 36 + 37 + # Layer 4: source code (changes frequently) 38 + COPY packages/ ./packages/ 39 + COPY apps/server/ ./apps/server/ 40 + 41 + # Patch server package.json too (COPY overwrote the patched version) 42 + RUN sh /tmp/patch-vendor-links.sh /app 43 + 44 + # Generate Prisma client 45 + WORKDIR /app/apps/server 46 + RUN pnpm exec prisma generate 47 + 48 + EXPOSE 3000 49 + 50 + CMD ["pnpm", "dev"] 51 + 52 + # ---- Production build ---- 53 + FROM node:24-bookworm-slim AS builder 54 + 55 + RUN apt-get update && apt-get install -y --no-install-recommends \ 56 + openssl build-essential python3 pkg-config \ 57 + libpixman-1-dev libcairo2-dev libpango1.0-dev \ 58 + libjpeg-dev libgif-dev librsvg2-dev \ 59 + && rm -rf /var/lib/apt/lists/* 60 + RUN corepack enable && corepack prepare pnpm@latest --activate 61 + 62 + WORKDIR /app 63 + 64 + COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 65 + COPY .docker/.manifests/ /tmp/manifests/ 66 + COPY .docker/restore-manifests.sh /tmp/ 67 + RUN sh /tmp/restore-manifests.sh /tmp/manifests 68 + 69 + COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 70 + COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 71 + COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 72 + COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 73 + COPY --from=project-q packages/transport/postgres/package.json ./vendor/project-q-transport-postgres/package.json 74 + COPY --from=project-q packages/transport/postgres/dist/ ./vendor/project-q-transport-postgres/dist/ 75 + 76 + COPY .docker/patch-vendor-links.sh /tmp/ 77 + RUN sh /tmp/patch-vendor-links.sh /app 78 + 79 + RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile 80 + 81 + COPY packages/ ./packages/ 82 + COPY apps/server/ ./apps/server/ 83 + RUN sh /tmp/patch-vendor-links.sh /app 84 + 85 + WORKDIR /app/apps/server 86 + RUN pnpm exec prisma generate 87 + WORKDIR /app 88 + RUN pnpm build 89 + 90 + # ---- Production runtime ---- 91 + FROM node:24-bookworm-slim AS production 92 + 93 + # canvas runtime libs (no build tools — prebuilt binaries from builder) 94 + RUN apt-get update && apt-get install -y --no-install-recommends \ 95 + openssl curl \ 96 + libcairo2 libpango-1.0-0 libpangocairo-1.0-0 \ 97 + libjpeg62-turbo libgif7 librsvg2-2 libpixman-1-0 \ 98 + && rm -rf /var/lib/apt/lists/* 99 + RUN corepack enable && corepack prepare pnpm@latest --activate 100 + 101 + WORKDIR /app 102 + 103 + COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 104 + COPY .docker/.manifests/ /tmp/manifests/ 105 + COPY .docker/restore-manifests.sh /tmp/ 106 + RUN sh /tmp/restore-manifests.sh /tmp/manifests 107 + 108 + COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 109 + COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 110 + COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 111 + COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 112 + COPY --from=project-q packages/transport/postgres/package.json ./vendor/project-q-transport-postgres/package.json 113 + COPY --from=project-q packages/transport/postgres/dist/ ./vendor/project-q-transport-postgres/dist/ 114 + 115 + COPY .docker/patch-vendor-links.sh /tmp/ 116 + RUN sh /tmp/patch-vendor-links.sh /app 117 + 118 + RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile --prod 119 + 120 + # Copy Prisma schema + generated client 121 + COPY apps/server/prisma/ ./apps/server/prisma/ 122 + COPY --from=builder /app/apps/server/node_modules/.prisma/ ./apps/server/node_modules/.prisma/ 123 + COPY --from=builder /app/node_modules/.prisma/ ./node_modules/.prisma/ 124 + 125 + # Copy compiled output 126 + COPY --from=builder /app/apps/server/dist/ ./apps/server/dist/ 127 + COPY --from=builder /app/packages/*/dist/ ./packages/ 128 + 129 + ENV NODE_ENV=production 130 + EXPOSE 3000 131 + 132 + WORKDIR /app/apps/server 133 + CMD ["node", "dist/main.js"]
+117
.docker/worker.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 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/postgres/package.json ./vendor/project-q-transport-postgres/package.json 23 + COPY --from=project-q packages/transport/postgres/dist/ ./vendor/project-q-transport-postgres/dist/ 24 + 25 + # Patch link: specifiers + create mount points for lockfile relative paths 26 + COPY .docker/patch-vendor-links.sh /tmp/ 27 + RUN sh /tmp/patch-vendor-links.sh /app 28 + 29 + # Layer 3: install (lockfile was patched above to match vendored paths) 30 + # shamefully-hoist makes all deps available at /app/node_modules/ so 31 + # vendored project-q packages (linked via link: protocol) can resolve 32 + # their transitive deps (uuid, zod, pg) through Node's upward walk. 33 + RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile 34 + 35 + # Layer 4: source code 36 + COPY packages/tsconfig/ ./packages/tsconfig/ 37 + COPY apps/worker/ ./apps/worker/ 38 + RUN sh /tmp/patch-vendor-links.sh /app 39 + 40 + # Install Chromium + system deps via Playwright 41 + RUN cd apps/worker && pnpm exec playwright install --with-deps chromium 42 + 43 + WORKDIR /app/apps/worker 44 + 45 + CMD ["pnpm", "dev"] 46 + 47 + # ---- Production build ---- 48 + FROM node:24-bookworm-slim AS builder 49 + 50 + RUN corepack enable && corepack prepare pnpm@latest --activate 51 + 52 + WORKDIR /app 53 + 54 + COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 55 + COPY .docker/.manifests/ /tmp/manifests/ 56 + COPY .docker/restore-manifests.sh /tmp/ 57 + RUN sh /tmp/restore-manifests.sh /tmp/manifests 58 + 59 + COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 60 + COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 61 + COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 62 + COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 63 + COPY --from=project-q packages/transport/postgres/package.json ./vendor/project-q-transport-postgres/package.json 64 + COPY --from=project-q packages/transport/postgres/dist/ ./vendor/project-q-transport-postgres/dist/ 65 + 66 + COPY .docker/patch-vendor-links.sh /tmp/ 67 + RUN sh /tmp/patch-vendor-links.sh /app 68 + 69 + # shamefully-hoist makes all deps available at /app/node_modules/ so 70 + # vendored project-q packages (linked via link: protocol) can resolve 71 + # their transitive deps (uuid, zod, pg) through Node's upward walk. 72 + RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile 73 + 74 + COPY packages/tsconfig/ ./packages/tsconfig/ 75 + COPY apps/worker/ ./apps/worker/ 76 + RUN sh /tmp/patch-vendor-links.sh /app 77 + 78 + WORKDIR /app/apps/worker 79 + RUN pnpm build 80 + 81 + # ---- Production runtime ---- 82 + FROM node:24-bookworm-slim AS production 83 + 84 + RUN corepack enable && corepack prepare pnpm@latest --activate 85 + 86 + WORKDIR /app 87 + 88 + COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 89 + COPY .docker/.manifests/ /tmp/manifests/ 90 + COPY .docker/restore-manifests.sh /tmp/ 91 + RUN sh /tmp/restore-manifests.sh /tmp/manifests 92 + 93 + COPY --from=project-q packages/core/package.json ./vendor/project-q-core/package.json 94 + COPY --from=project-q packages/core/dist/ ./vendor/project-q-core/dist/ 95 + COPY --from=project-q packages/framework/nest/package.json ./vendor/project-q-nestjs/package.json 96 + COPY --from=project-q packages/framework/nest/dist/ ./vendor/project-q-nestjs/dist/ 97 + COPY --from=project-q packages/transport/postgres/package.json ./vendor/project-q-transport-postgres/package.json 98 + COPY --from=project-q packages/transport/postgres/dist/ ./vendor/project-q-transport-postgres/dist/ 99 + 100 + COPY .docker/patch-vendor-links.sh /tmp/ 101 + RUN sh /tmp/patch-vendor-links.sh /app 102 + 103 + # shamefully-hoist makes all deps available at /app/node_modules/ so 104 + # vendored project-q packages (linked via link: protocol) can resolve 105 + # their transitive deps (uuid, zod, pg) through Node's upward walk. 106 + RUN NPM_CONFIG_SHAMEFULLY_HOIST=true pnpm install --frozen-lockfile --prod 107 + 108 + # Install Chromium + system deps via Playwright 109 + RUN cd apps/worker && pnpm exec playwright install --with-deps chromium 110 + 111 + # Copy compiled output 112 + COPY --from=builder /app/apps/worker/dist/ ./apps/worker/dist/ 113 + 114 + ENV NODE_ENV=production 115 + 116 + WORKDIR /app/apps/worker 117 + CMD ["node", "dist/main.js"]
+3 -1
.dockerignore
··· 29 29 .gitignore 30 30 31 31 # Docker 32 - Dockerfile* 33 32 docker-compose*.yml 34 33 .dockerignore 34 + 35 + # Keep .docker dir (Dockerfiles + manifests) 36 + !.docker/ 35 37 36 38 # Logs 37 39 logs/
+3
.env.example
··· 58 58 # LINKEDIN_CLIENT_ID= 59 59 # LINKEDIN_CLIENT_SECRET= 60 60 # LINKEDIN_REDIRECT_URI=http://localhost:5173/auth/linkedin/callback 61 + 62 + # project-q / Worker 63 + # PROJECT_Q_PATH=/path/to/project-q # Only needed for docker compose build
+9
.gitignore
··· 69 69 test-*.sh 70 70 test-prompt.json 71 71 72 + # Real-world test fixtures (contain PII) 73 + packages/file-upload/src/__tests__/fixtures/* 74 + !packages/file-upload/src/__tests__/fixtures/.gitkeep 75 + apps/server/test/assets/* 76 + !apps/server/test/assets/.gitkeep 77 + 72 78 # Coverage reports (outside coverage/) 73 79 **/coverage-unit/ 74 80 ··· 88 94 89 95 # Local scripts 90 96 scripts/ 97 + 98 + # Docker manifest staging (generated by .docker/copy-manifests.sh) 99 + .docker/.manifests/
-48
apps/client/Dockerfile
··· 1 - FROM node:24-alpine AS development 2 - 3 - RUN apk add --no-cache curl 4 - RUN corepack enable && corepack prepare pnpm@latest --activate 5 - 6 - WORKDIR /app 7 - 8 - # Copy monorepo files 9 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 10 - COPY packages/ ./packages/ 11 - COPY apps/ ./apps/ 12 - COPY scripts/ ./scripts/ 13 - 14 - # Install dependencies 15 - RUN pnpm install --frozen-lockfile 16 - 17 - EXPOSE 5173 18 - 19 - WORKDIR /app/apps/client 20 - CMD ["pnpm", "dev"] 21 - 22 - # Production build stage 23 - FROM node:24-alpine AS builder 24 - 25 - RUN corepack enable && corepack prepare pnpm@latest --activate 26 - 27 - WORKDIR /app 28 - 29 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 30 - COPY packages/ ./packages/ 31 - COPY apps/ ./apps/ 32 - 33 - RUN pnpm install --frozen-lockfile 34 - 35 - COPY apps/client/ ./apps/client/ 36 - 37 - WORKDIR /app/apps/client 38 - RUN pnpm build 39 - 40 - # Production serve stage 41 - FROM nginx:alpine AS production 42 - 43 - COPY --from=builder /app/apps/client/dist /usr/share/nginx/html 44 - COPY apps/client/nginx.conf /etc/nginx/conf.d/default.conf 45 - 46 - EXPOSE 80 47 - 48 - CMD ["nginx", "-g", "daemon off;"]
-48
apps/docs/Dockerfile
··· 1 - FROM node:24-alpine AS development 2 - 3 - RUN apk add --no-cache curl 4 - RUN corepack enable && corepack prepare pnpm@latest --activate 5 - 6 - WORKDIR /app 7 - 8 - # Copy monorepo files 9 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 10 - COPY packages/ ./packages/ 11 - COPY apps/ ./apps/ 12 - COPY scripts/ ./scripts/ 13 - 14 - # Install dependencies 15 - RUN pnpm install --frozen-lockfile 16 - 17 - EXPOSE 3001 18 - 19 - WORKDIR /app/apps/docs 20 - CMD ["pnpm", "dev"] 21 - 22 - # Production build stage 23 - FROM node:24-alpine AS builder 24 - 25 - RUN corepack enable && corepack prepare pnpm@latest --activate 26 - 27 - WORKDIR /app 28 - 29 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 30 - COPY packages/ ./packages/ 31 - COPY apps/ ./apps/ 32 - 33 - RUN pnpm install --frozen-lockfile 34 - 35 - COPY apps/docs/ ./apps/docs/ 36 - 37 - WORKDIR /app/apps/docs 38 - RUN pnpm build 39 - 40 - # Production serve stage 41 - FROM nginx:alpine AS production 42 - 43 - COPY --from=builder /app/apps/docs/dist /usr/share/nginx/html 44 - COPY apps/docs/nginx.conf /etc/nginx/conf.d/default.conf 45 - 46 - EXPOSE 80 47 - 48 - CMD ["nginx", "-g", "daemon off;"]
-78
apps/server/Dockerfile
··· 1 - FROM node:24-alpine AS development 2 - 3 - RUN apk add --no-cache curl openssl 4 - RUN corepack enable && corepack prepare pnpm@latest --activate 5 - 6 - WORKDIR /app 7 - 8 - # Copy root package files 9 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 10 - 11 - # Copy all packages and apps 12 - COPY packages/ ./packages/ 13 - COPY apps/ ./apps/ 14 - 15 - # Copy health check scripts 16 - COPY scripts/ ./scripts/ 17 - 18 - # Install dependencies 19 - RUN pnpm install --frozen-lockfile 20 - 21 - # Generate Prisma client 22 - WORKDIR /app/apps/server 23 - RUN pnpm exec prisma generate 24 - WORKDIR /app 25 - 26 - EXPOSE 3000 27 - 28 - WORKDIR /app/apps/server 29 - CMD ["pnpm", "dev"] 30 - 31 - # ---- Production build ---- 32 - FROM node:24-alpine AS builder 33 - 34 - RUN apk add --no-cache openssl 35 - RUN corepack enable && corepack prepare pnpm@latest --activate 36 - 37 - WORKDIR /app 38 - 39 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 40 - COPY packages/ ./packages/ 41 - COPY apps/ ./apps/ 42 - 43 - RUN pnpm install --frozen-lockfile 44 - 45 - WORKDIR /app/apps/server 46 - RUN pnpm exec prisma generate 47 - WORKDIR /app 48 - 49 - RUN pnpm build 50 - 51 - # ---- Production runtime ---- 52 - FROM node:24-alpine AS production 53 - 54 - RUN apk add --no-cache openssl curl 55 - RUN corepack enable && corepack prepare pnpm@latest --activate 56 - 57 - WORKDIR /app 58 - 59 - COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 60 - COPY packages/ ./packages/ 61 - COPY apps/server/package.json ./apps/server/ 62 - 63 - RUN pnpm install --frozen-lockfile --prod 64 - 65 - # Copy Prisma schema + generated client 66 - COPY apps/server/prisma/ ./apps/server/prisma/ 67 - COPY --from=builder /app/apps/server/node_modules/.prisma/ ./apps/server/node_modules/.prisma/ 68 - COPY --from=builder /app/node_modules/.prisma/ ./node_modules/.prisma/ 69 - 70 - # Copy compiled output 71 - COPY --from=builder /app/apps/server/dist/ ./apps/server/dist/ 72 - COPY --from=builder /app/packages/*/dist/ ./packages/ 73 - 74 - ENV NODE_ENV=production 75 - EXPOSE 3000 76 - 77 - WORKDIR /app/apps/server 78 - CMD ["node", "dist/main.js"]
+53 -14
docker-compose.yml
··· 18 18 server: 19 19 build: 20 20 context: . 21 - dockerfile: apps/server/Dockerfile 21 + dockerfile: .docker/server.Dockerfile 22 + target: development 23 + additional_contexts: 24 + project-q: ${PROJECT_Q_PATH:?Set PROJECT_Q_PATH to your local project-q checkout} 22 25 environment: 23 26 PORT: ${SERVER_PORT:-3000} 24 27 JWT_SECRET: ${JWT_SECRET:-your-super-secret-jwt-key-here} ··· 30 33 POSTGRES_DB: ${POSTGRES_DB:-cv} 31 34 ENCRYPTION_KEY: ${ENCRYPTION_KEY:-dev-encryption-key-32-chars-long!} 32 35 RESEND_API_KEY: ${RESEND_API_KEY:-} 33 - LLAMA_URL: ${LLAMA_URL:-http://llama:8080} 36 + LLAMA_URL: ${LLAMA_URL:-http://host.docker.internal:8080} 34 37 AI_TIMEOUT: ${AI_TIMEOUT:-300000} 35 - AI_MAX_TOKENS: ${AI_MAX_TOKENS:-4096} 38 + AI_MAX_TOKENS: ${AI_MAX_TOKENS:-8192} 39 + PDF_OUTPUT_DIR: /app/pdf-output 36 40 depends_on: 37 41 db: 38 42 condition: service_healthy ··· 41 45 volumes: 42 46 - ./apps/server/src:/app/apps/server/src 43 47 - ./apps/server/prisma:/app/apps/server/prisma 44 - - ./packages:/app/packages 45 - - pnpm-cache:/root/.local/share/pnpm 46 - command: sh -c "cd /app/apps/server && pnpm prisma:deploy && pnpm dev" 48 + - ./packages/ai-parser/src:/app/packages/ai-parser/src 49 + - ./packages/ai-provider/src:/app/packages/ai-provider/src 50 + - ./packages/auth/src:/app/packages/auth/src 51 + - ./packages/cv-renderer/src:/app/packages/cv-renderer/src 52 + - ./packages/file-upload/src:/app/packages/file-upload/src 53 + - ./packages/system/src:/app/packages/system/src 54 + - worker-output:/app/pdf-output:ro 55 + command: sh -c "cd /app/apps/server && pnpm prisma generate && pnpm prisma:deploy && pnpm dev" 47 56 healthcheck: 48 57 test: ["CMD", "curl", "-f", "http://localhost:3000/health"] 49 58 interval: 15s ··· 54 63 client: 55 64 build: 56 65 context: . 57 - dockerfile: apps/client/Dockerfile 66 + dockerfile: .docker/client.Dockerfile 58 67 target: development 59 68 environment: 60 69 VITE_SERVER_URL: ${VITE_SERVER_URL:-http://localhost:3000} ··· 68 77 - "${CLIENT_PORT:-5173}:5173" 69 78 volumes: 70 79 - ./apps/client/src:/app/apps/client/src 71 - - ./packages:/app/packages 72 - - pnpm-cache:/root/.local/share/pnpm 80 + - ./packages/routing/src:/app/packages/routing/src 81 + - ./packages/ui/src:/app/packages/ui/src 82 + - ./packages/system/src:/app/packages/system/src 73 83 command: sh -c "cd /app/apps/client && (pnpm codegen || true) && pnpm dev" 74 84 healthcheck: 75 85 test: ["CMD", "curl", "-f", "http://localhost:5173"] ··· 78 88 retries: 3 79 89 start_period: 20s 80 90 91 + worker: 92 + build: 93 + context: . 94 + dockerfile: .docker/worker.Dockerfile 95 + target: development 96 + additional_contexts: 97 + project-q: ${PROJECT_Q_PATH:?Set PROJECT_Q_PATH to your local project-q checkout} 98 + environment: 99 + DATABASE_URL: ${DATABASE_URL:-postgresql://cv:cv@db:5432/cv} 100 + QUEUE_SCHEMA: ${QUEUE_SCHEMA:-queue} 101 + QUEUE_NAME: ${QUEUE_NAME:-default} 102 + POLL_INTERVAL_MS: ${POLL_INTERVAL_MS:-1000} 103 + PDF_OUTPUT_DIR: /app/pdf-output 104 + HEARTBEAT_FILE_PATH: /tmp/worker-heartbeat 105 + depends_on: 106 + db: 107 + condition: service_healthy 108 + volumes: 109 + - ./apps/worker/src:/app/apps/worker/src 110 + - worker-output:/app/pdf-output 111 + restart: unless-stopped 112 + healthcheck: 113 + test: ["CMD-SHELL", "find /tmp/worker-heartbeat -mmin -1 | grep -q ."] 114 + interval: 30s 115 + timeout: 5s 116 + retries: 3 117 + start_period: 10s 118 + 81 119 docs: 82 120 build: 83 121 context: . 84 - dockerfile: apps/docs/Dockerfile 122 + dockerfile: .docker/docs.Dockerfile 85 123 target: development 86 124 environment: 87 125 VITE_CLIENT_URL: ${VITE_CLIENT_URL:-http://localhost:5173} ··· 91 129 volumes: 92 130 - ./apps/docs/src:/app/apps/docs/src 93 131 - ./apps/docs/content:/app/apps/docs/content 94 - - ./packages:/app/packages 95 - - pnpm-cache:/root/.local/share/pnpm 132 + - ./packages/routing/src:/app/packages/routing/src 133 + - ./packages/ui/src:/app/packages/ui/src 134 + - ./packages/system/src:/app/packages/system/src 96 135 healthcheck: 97 136 test: ["CMD", "curl", "-f", "http://localhost:3001"] 98 137 interval: 15s ··· 130 169 - "${LLAMA_PORT:-8080}:8080" 131 170 volumes: 132 171 - ./ai-models:/models 133 - command: -m /models/mistral-7b-instruct-v0.2.Q4_K_M.gguf --port 8080 --host 0.0.0.0 -c 4096 -ngl 0 # -ngl 0 = CPU only 172 + command: -m /models/mistral-7b-instruct-v0.2.Q4_K_M.gguf --port 8080 --host 0.0.0.0 -c 16384 -ngl 0 # -ngl 0 = CPU only 134 173 depends_on: 135 174 model-download: 136 175 condition: service_completed_successfully ··· 143 182 144 183 volumes: 145 184 db-data: 146 - pnpm-cache: 185 + worker-output: