feat(v2): full spec implementation — root SSH, bootstrap sentinel, HMAC webhook, all parametric routes fixed #1
@@ -0,0 +1,4 @@
|
|||||||
|
# Copy to .env.docker and fill in real values before running docker compose
|
||||||
|
SESSION_SECRET=change_me_min_32_chars_random_hex
|
||||||
|
PP_BASE_URL=http://localhost:5000
|
||||||
|
ENCRYPTION_KEY=change_me_64_hex_chars_used_to_encrypt_gitea_and_aws_credentials
|
||||||
@@ -2,6 +2,7 @@ node_modules/
|
|||||||
backend/dist/
|
backend/dist/
|
||||||
frontend/dist/
|
frontend/dist/
|
||||||
.env
|
.env
|
||||||
|
.env.docker
|
||||||
*.env.local
|
*.env.local
|
||||||
*.log
|
*.log
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
+33
-14
@@ -1,22 +1,41 @@
|
|||||||
FROM node:24-alpine AS frontend-builder
|
# Stage 1: Install all workspace dependencies
|
||||||
WORKDIR /app/frontend
|
# Using workspace-level install so pnpm-workspace.yaml settings (onlyBuiltDependencies,
|
||||||
COPY frontend/package.json frontend/pnpm-lock.yaml* ./
|
# supply-chain policies, etc.) apply uniformly — the canonical pnpm monorepo pattern.
|
||||||
RUN npm install -g pnpm && pnpm install --frozen-lockfile
|
FROM node:24-alpine AS deps
|
||||||
COPY frontend/ ./
|
WORKDIR /app
|
||||||
RUN pnpm build
|
|
||||||
|
|
||||||
FROM node:24-alpine AS backend-builder
|
# Copy workspace manifest files first for layer caching
|
||||||
WORKDIR /app/backend
|
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||||
COPY backend/package.json backend/pnpm-lock.yaml* ./
|
COPY frontend/package.json ./frontend/
|
||||||
RUN npm install -g pnpm && pnpm install --frozen-lockfile
|
COPY backend/package.json ./backend/
|
||||||
COPY backend/ ./
|
COPY prisma/ ./prisma/
|
||||||
COPY prisma/ ../prisma/
|
|
||||||
RUN pnpm run generate && pnpm run build
|
|
||||||
|
|
||||||
|
# corepack activates the exact pnpm version declared in package.json#packageManager.
|
||||||
|
# This is hash-verified (sha1) and prevents newer pnpm from applying different
|
||||||
|
# supply-chain policies (e.g. minimumReleaseAge) against a lockfile generated with
|
||||||
|
# the pinned version.
|
||||||
|
RUN corepack enable && corepack install && \
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Stage 2: Build frontend
|
||||||
|
FROM deps AS frontend-builder
|
||||||
|
COPY frontend/ ./frontend/
|
||||||
|
RUN pnpm --filter pp-frontend run build
|
||||||
|
|
||||||
|
# Stage 3: Build backend + Prisma client
|
||||||
|
FROM deps AS backend-builder
|
||||||
|
COPY backend/ ./backend/
|
||||||
|
RUN pnpm --filter pp-backend run generate && \
|
||||||
|
pnpm --filter pp-backend run build
|
||||||
|
|
||||||
|
# Stage 4: Minimal production runner
|
||||||
FROM node:24-alpine AS runner
|
FROM node:24-alpine AS runner
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN apk add --no-cache openssl
|
RUN apk add --no-cache openssl
|
||||||
|
|
||||||
|
# Root node_modules contains prisma CLI and hoisted deps; backend node_modules has
|
||||||
|
# the backend-specific symlinks. Both are needed at runtime.
|
||||||
|
COPY --from=backend-builder /app/node_modules ./node_modules
|
||||||
COPY --from=backend-builder /app/backend/dist ./backend/dist
|
COPY --from=backend-builder /app/backend/dist ./backend/dist
|
||||||
COPY --from=backend-builder /app/backend/node_modules ./backend/node_modules
|
COPY --from=backend-builder /app/backend/node_modules ./backend/node_modules
|
||||||
COPY --from=backend-builder /app/backend/package.json ./backend/package.json
|
COPY --from=backend-builder /app/backend/package.json ./backend/package.json
|
||||||
@@ -27,4 +46,4 @@ WORKDIR /app/backend
|
|||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
CMD sh -c "npx prisma migrate deploy --schema=../prisma/schema.prisma && node dist/index.js"
|
CMD sh -c "../node_modules/.bin/prisma migrate deploy --schema=../prisma/schema.prisma && node dist/index.js"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "PR Previews backend",
|
"description": "PR Previews backend",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"packageManager": "pnpm@11.5.2+sha1.7ab39d363d1ca5b2fb97795f45291083da4a1393",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "rimraf dist && esbuild \"src/**/*.ts\" --platform=node --sourcemap --ignore-annotations --format=cjs --target=es2022 --outdir=dist && cd dist && node index.js",
|
"dev": "rimraf dist && esbuild \"src/**/*.ts\" --platform=node --sourcemap --ignore-annotations --format=cjs --target=es2022 --outdir=dist && cd dist && node index.js",
|
||||||
"build": "rimraf dist && esbuild \"src/**/*.ts\" --platform=node --sourcemap --ignore-annotations --format=cjs --target=es2022 --outdir=dist",
|
"build": "rimraf dist && esbuild \"src/**/*.ts\" --platform=node --sourcemap --ignore-annotations --format=cjs --target=es2022 --outdir=dist",
|
||||||
|
|||||||
+1
-3
@@ -1,5 +1,3 @@
|
|||||||
version: "3.9"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
pp-db:
|
pp-db:
|
||||||
image: postgres:18-alpine
|
image: postgres:18-alpine
|
||||||
@@ -9,7 +7,7 @@ services:
|
|||||||
POSTGRES_PASSWORD: pp_password
|
POSTGRES_PASSWORD: pp_password
|
||||||
POSTGRES_DB: pp
|
POSTGRES_DB: pp
|
||||||
volumes:
|
volumes:
|
||||||
- pp_db_data:/var/lib/postgresql/data
|
- pp_db_data:/var/lib/postgresql
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U pp"]
|
test: ["CMD-SHELL", "pg_isready -U pp"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"name": "pp-frontend",
|
"name": "pp-frontend",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"packageManager": "pnpm@11.5.2+sha1.7ab39d363d1ca5b2fb97795f45291083da4a1393",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@@ -9,18 +10,18 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"motion": "^12.0.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-router-dom": "^7.0.0",
|
"react-router-dom": "^7.0.0",
|
||||||
"react-toastify": "^11.0.0",
|
"react-toastify": "^11.0.0"
|
||||||
"motion": "^12.0.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^19.0.0",
|
"@types/react": "^19.0.0",
|
||||||
"@types/react-dom": "^19.0.0",
|
"@types/react-dom": "^19.0.0",
|
||||||
"@vitejs/plugin-react": "^4.3.0",
|
"@vitejs/plugin-react": "^4.3.0",
|
||||||
"autoprefixer": "^10.4.0",
|
"autoprefixer": "^10.4.0",
|
||||||
"postcss": "^8.4.0",
|
"postcss": "^8.5.22",
|
||||||
"tailwindcss": "^3.4.0",
|
"tailwindcss": "^3.4.0",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^6.0.0"
|
"vite": "^6.0.0"
|
||||||
|
|||||||
Generated
+22
-22
@@ -35,10 +35,10 @@ importers:
|
|||||||
version: 4.7.0(vite@6.4.3(jiti@1.21.7))
|
version: 4.7.0(vite@6.4.3(jiti@1.21.7))
|
||||||
autoprefixer:
|
autoprefixer:
|
||||||
specifier: ^10.4.0
|
specifier: ^10.4.0
|
||||||
version: 10.5.4(postcss@8.5.23)
|
version: 10.5.4(postcss@8.5.22)
|
||||||
postcss:
|
postcss:
|
||||||
specifier: ^8.4.0
|
specifier: ^8.5.22
|
||||||
version: 8.5.23
|
version: 8.5.22
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.4.0
|
specifier: ^3.4.0
|
||||||
version: 3.4.19
|
version: 3.4.19
|
||||||
@@ -820,8 +820,8 @@ packages:
|
|||||||
postcss-value-parser@4.2.0:
|
postcss-value-parser@4.2.0:
|
||||||
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
|
||||||
|
|
||||||
postcss@8.5.23:
|
postcss@8.5.22:
|
||||||
resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==}
|
resolution: {integrity: sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==}
|
||||||
engines: {node: ^10 || ^12 || >=14}
|
engines: {node: ^10 || ^12 || >=14}
|
||||||
|
|
||||||
queue-microtask@1.2.3:
|
queue-microtask@1.2.3:
|
||||||
@@ -1347,13 +1347,13 @@ snapshots:
|
|||||||
|
|
||||||
arg@5.0.2: {}
|
arg@5.0.2: {}
|
||||||
|
|
||||||
autoprefixer@10.5.4(postcss@8.5.23):
|
autoprefixer@10.5.4(postcss@8.5.22):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.28.7
|
browserslist: 4.28.7
|
||||||
caniuse-lite: 1.0.30001806
|
caniuse-lite: 1.0.30001806
|
||||||
fraction.js: 5.3.4
|
fraction.js: 5.3.4
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
postcss: 8.5.23
|
postcss: 8.5.22
|
||||||
postcss-value-parser: 4.2.0
|
postcss-value-parser: 4.2.0
|
||||||
|
|
||||||
baseline-browser-mapping@2.11.1: {}
|
baseline-browser-mapping@2.11.1: {}
|
||||||
@@ -1576,28 +1576,28 @@ snapshots:
|
|||||||
|
|
||||||
pirates@4.0.7: {}
|
pirates@4.0.7: {}
|
||||||
|
|
||||||
postcss-import@15.1.0(postcss@8.5.23):
|
postcss-import@15.1.0(postcss@8.5.22):
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 8.5.23
|
postcss: 8.5.22
|
||||||
postcss-value-parser: 4.2.0
|
postcss-value-parser: 4.2.0
|
||||||
read-cache: 1.0.0
|
read-cache: 1.0.0
|
||||||
resolve: 1.22.12
|
resolve: 1.22.12
|
||||||
|
|
||||||
postcss-js@4.1.0(postcss@8.5.23):
|
postcss-js@4.1.0(postcss@8.5.22):
|
||||||
dependencies:
|
dependencies:
|
||||||
camelcase-css: 2.0.1
|
camelcase-css: 2.0.1
|
||||||
postcss: 8.5.23
|
postcss: 8.5.22
|
||||||
|
|
||||||
postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.23):
|
postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.22):
|
||||||
dependencies:
|
dependencies:
|
||||||
lilconfig: 3.1.3
|
lilconfig: 3.1.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
jiti: 1.21.7
|
jiti: 1.21.7
|
||||||
postcss: 8.5.23
|
postcss: 8.5.22
|
||||||
|
|
||||||
postcss-nested@6.2.0(postcss@8.5.23):
|
postcss-nested@6.2.0(postcss@8.5.22):
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 8.5.23
|
postcss: 8.5.22
|
||||||
postcss-selector-parser: 6.1.4
|
postcss-selector-parser: 6.1.4
|
||||||
|
|
||||||
postcss-selector-parser@6.1.4:
|
postcss-selector-parser@6.1.4:
|
||||||
@@ -1607,7 +1607,7 @@ snapshots:
|
|||||||
|
|
||||||
postcss-value-parser@4.2.0: {}
|
postcss-value-parser@4.2.0: {}
|
||||||
|
|
||||||
postcss@8.5.23:
|
postcss@8.5.22:
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: 3.3.16
|
nanoid: 3.3.16
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
@@ -1732,11 +1732,11 @@ snapshots:
|
|||||||
normalize-path: 3.0.0
|
normalize-path: 3.0.0
|
||||||
object-hash: 3.0.0
|
object-hash: 3.0.0
|
||||||
picocolors: 1.1.1
|
picocolors: 1.1.1
|
||||||
postcss: 8.5.23
|
postcss: 8.5.22
|
||||||
postcss-import: 15.1.0(postcss@8.5.23)
|
postcss-import: 15.1.0(postcss@8.5.22)
|
||||||
postcss-js: 4.1.0(postcss@8.5.23)
|
postcss-js: 4.1.0(postcss@8.5.22)
|
||||||
postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.23)
|
postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.22)
|
||||||
postcss-nested: 6.2.0(postcss@8.5.23)
|
postcss-nested: 6.2.0(postcss@8.5.22)
|
||||||
postcss-selector-parser: 6.1.4
|
postcss-selector-parser: 6.1.4
|
||||||
resolve: 1.22.12
|
resolve: 1.22.12
|
||||||
sucrase: 3.35.1
|
sucrase: 3.35.1
|
||||||
@@ -1780,7 +1780,7 @@ snapshots:
|
|||||||
esbuild: 0.25.12
|
esbuild: 0.25.12
|
||||||
fdir: 6.5.0(picomatch@4.0.5)
|
fdir: 6.5.0(picomatch@4.0.5)
|
||||||
picomatch: 4.0.5
|
picomatch: 4.0.5
|
||||||
postcss: 8.5.23
|
postcss: 8.5.22
|
||||||
rollup: 4.62.2
|
rollup: 4.62.2
|
||||||
tinyglobby: 0.2.17
|
tinyglobby: 0.2.17
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"name": "pp",
|
||||||
|
"private": true,
|
||||||
|
"packageManager": "pnpm@11.5.2+sha1.7ab39d363d1ca5b2fb97795f45291083da4a1393",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prisma": "^6.19.3"
|
"prisma": "^6.19.3"
|
||||||
},
|
},
|
||||||
|
|||||||
Generated
+3723
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -2,13 +2,13 @@ packages:
|
|||||||
- backend
|
- backend
|
||||||
- frontend
|
- frontend
|
||||||
allowBuilds:
|
allowBuilds:
|
||||||
'@prisma/client': set this to true or false
|
'@prisma/client': true
|
||||||
'@prisma/engines': set this to true or false
|
'@prisma/engines': true
|
||||||
bufferutil: set this to true or false
|
bufferutil: true
|
||||||
cpu-features: set this to true or false
|
cpu-features: true
|
||||||
esbuild: set this to true or false
|
esbuild: true
|
||||||
prisma: set this to true or false
|
prisma: true
|
||||||
ssh2: set this to true or false
|
ssh2: true
|
||||||
onlyBuiltDependencies:
|
onlyBuiltDependencies:
|
||||||
- '@prisma/client'
|
- '@prisma/client'
|
||||||
- '@prisma/engines'
|
- '@prisma/engines'
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
|
binaryTargets = ["native", "debian-openssl-3.0.x", "linux-musl-openssl-3.0.x"]
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
|
|||||||
Reference in New Issue
Block a user