feat(repo): migrate chronomind workspace to pnpm
- Add pnpm-workspace.yaml (backend + web + common-plat packages) - Add root package.json with workspace scripts and pnpm config - Add packageManager: pnpm@10.6.5 to backend/web manifests - Remove package-lock.json files, generate pnpm-lock.yaml - Add root .gitignore (was missing) - Update CI to use pnpm workspace commands - Add transpilePackages + webpack symlinks to next.config.ts - Update docker-prep.sh for backend + web consumers - Rewrite backend/web Dockerfiles to .docker-deps consumer pattern - Add .dockerignore Verified: typecheck + 576 tests (182 backend + 394 web) + builds pass Docker: backend + web smoke builds pass
This commit is contained in:
parent
ab400fbb6a
commit
582936ad65
9
.dockerignore
Normal file
9
.dockerignore
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
node_modules
|
||||||
|
backend/node_modules
|
||||||
|
web/node_modules
|
||||||
|
backend/dist
|
||||||
|
web/.next
|
||||||
|
*.log
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
pnpm-lock.yaml
|
||||||
56
.github/workflows/ci.yml
vendored
56
.github/workflows/ci.yml
vendored
@ -28,8 +28,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
|
|
||||||
- name: Install pnpm (for common-plat build)
|
- name: Install pnpm
|
||||||
run: npm install -g pnpm
|
run: npm install -g pnpm@10.6.5
|
||||||
|
|
||||||
- name: Build @bytelyst/* packages
|
- name: Build @bytelyst/* packages
|
||||||
working-directory: learning_ai_common_plat
|
working-directory: learning_ai_common_plat
|
||||||
@ -37,17 +37,14 @@ jobs:
|
|||||||
pnpm install --frozen-lockfile
|
pnpm install --frozen-lockfile
|
||||||
pnpm build
|
pnpm build
|
||||||
|
|
||||||
- name: Install backend dependencies
|
- name: Install workspace dependencies
|
||||||
working-directory: backend
|
run: pnpm install
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Backend typecheck
|
- name: Backend typecheck
|
||||||
working-directory: backend
|
run: pnpm --filter @chronomind/backend run typecheck
|
||||||
run: npm run typecheck
|
|
||||||
|
|
||||||
- name: Backend tests
|
- name: Backend tests
|
||||||
working-directory: backend
|
run: pnpm --filter @chronomind/backend run test
|
||||||
run: npm test
|
|
||||||
env:
|
env:
|
||||||
DB_PROVIDER: memory
|
DB_PROVIDER: memory
|
||||||
JWT_SECRET: ci-test-secret-at-least-32-characters-long
|
JWT_SECRET: ci-test-secret-at-least-32-characters-long
|
||||||
@ -55,25 +52,42 @@ jobs:
|
|||||||
web:
|
web:
|
||||||
name: Web — typecheck + lint + test
|
name: Web — typecheck + lint + test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
working-directory: web
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Checkout common-plat (for @bytelyst/* packages)
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: saravanakumardb1/learning_ai_common_plat
|
||||||
|
path: learning_ai_common_plat
|
||||||
|
token: ${{ secrets.GH_PAT }}
|
||||||
|
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version: 22
|
||||||
cache: npm
|
|
||||||
cache-dependency-path: web/package-lock.json
|
|
||||||
|
|
||||||
- run: npm ci
|
- name: Install pnpm
|
||||||
|
run: npm install -g pnpm@10.6.5
|
||||||
|
|
||||||
- name: Typecheck
|
- name: Build @bytelyst/* packages
|
||||||
run: npx tsc --noEmit
|
working-directory: learning_ai_common_plat
|
||||||
|
run: |
|
||||||
|
pnpm install --frozen-lockfile
|
||||||
|
pnpm build
|
||||||
|
|
||||||
- name: Lint
|
- name: Install workspace dependencies
|
||||||
run: npm run lint
|
run: pnpm install
|
||||||
|
|
||||||
- name: Test
|
- name: Web typecheck
|
||||||
run: npm test
|
run: pnpm --filter web run typecheck
|
||||||
|
|
||||||
|
- name: Web lint
|
||||||
|
run: pnpm --filter web run lint
|
||||||
|
|
||||||
|
- name: Web test
|
||||||
|
run: pnpm --filter web run test
|
||||||
|
|
||||||
|
- name: Web build
|
||||||
|
run: pnpm --filter web run build
|
||||||
|
env:
|
||||||
|
NEXT_TELEMETRY_DISABLED: '1'
|
||||||
|
|||||||
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.next
|
||||||
|
*.log
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
.DS_Store
|
||||||
@ -1,26 +1,38 @@
|
|||||||
# Pre-requisite: run ./scripts/docker-prep.sh to pack @bytelyst/* tarballs
|
# Pre-requisite: run ./scripts/docker-prep.sh to pack @bytelyst/* tarballs
|
||||||
FROM node:22-alpine AS builder
|
# ── Stage 1: Build ────────────────────────────────────
|
||||||
WORKDIR /app
|
FROM node:22-slim AS builder
|
||||||
|
WORKDIR /app/backend
|
||||||
|
ENV NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||||
|
|
||||||
COPY package.json package-lock.json ./
|
RUN npm config set strict-ssl false
|
||||||
COPY .tarballs/ ./.tarballs/
|
COPY backend/package.json ./package.json
|
||||||
RUN npm ci --ignore-scripts
|
COPY backend/.docker-deps/ ./.docker-deps/
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
COPY tsconfig.json ./
|
COPY backend/tsconfig.json ./tsconfig.json
|
||||||
COPY src/ ./src/
|
COPY backend/src/ ./src/
|
||||||
RUN npx tsc
|
COPY shared/ ../shared/
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
# Production stage
|
# ── Stage 2: Prod deps ───────────────────────────────
|
||||||
FROM node:22-alpine
|
FROM node:22-slim AS deps
|
||||||
WORKDIR /app
|
WORKDIR /app/backend
|
||||||
|
ENV NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||||
|
|
||||||
|
RUN npm config set strict-ssl false
|
||||||
|
COPY backend/package.json ./package.json
|
||||||
|
COPY backend/.docker-deps/ ./.docker-deps/
|
||||||
|
RUN npm install --omit=dev
|
||||||
|
|
||||||
|
# ── Stage 3: Runtime ──────────────────────────────────
|
||||||
|
FROM node:22-slim
|
||||||
|
WORKDIR /app/backend
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
COPY package.json package-lock.json ./
|
COPY --from=deps /app/backend/node_modules ./node_modules
|
||||||
COPY .tarballs/ ./.tarballs/
|
COPY --from=deps /app/backend/package.json ./package.json
|
||||||
RUN npm ci --omit=dev --ignore-scripts
|
COPY --from=builder /app/backend/dist ./dist
|
||||||
|
COPY shared/product.json ../shared/product.json
|
||||||
COPY --from=builder /app/dist ./dist
|
|
||||||
COPY shared/ ./shared/ 2>/dev/null || true
|
|
||||||
|
|
||||||
EXPOSE 4011
|
EXPOSE 4011
|
||||||
CMD ["node", "dist/server.js"]
|
CMD ["node", "dist/server.js"]
|
||||||
|
|||||||
2804
backend/package-lock.json
generated
2804
backend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
|||||||
"name": "@chronomind/backend",
|
"name": "@chronomind/backend",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"packageManager": "pnpm@10.6.5",
|
||||||
"description": "ChronoMind product-specific backend — timers, routines, households, shared timers",
|
"description": "ChronoMind product-specific backend — timers, routines, households, shared timers",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
12
package.json
Normal file
12
package.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "@chronomind/root",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"packageManager": "pnpm@10.6.5",
|
||||||
|
"scripts": {
|
||||||
|
"verify": "pnpm --filter @chronomind/backend run typecheck && pnpm --filter @chronomind/backend run test && pnpm --filter @chronomind/backend run build && pnpm --filter web run typecheck && pnpm --filter web run test && pnpm --filter web run build"
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"onlyBuiltDependencies": ["esbuild", "sharp"]
|
||||||
|
}
|
||||||
|
}
|
||||||
12703
pnpm-lock.yaml
generated
Normal file
12703
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
4
pnpm-workspace.yaml
Normal file
4
pnpm-workspace.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
packages:
|
||||||
|
- backend
|
||||||
|
- web
|
||||||
|
- ../learning_ai_common_plat/packages/*
|
||||||
@ -1,33 +1,27 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# docker-prep.sh — Pack @bytelyst/* packages as tarballs for Docker/CI builds.
|
|
||||||
# Delegates to the universal prep-consumer.sh in learning_ai_common_plat.
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# ./scripts/docker-prep.sh # prep for docker build
|
|
||||||
# ./scripts/docker-prep.sh --restore # undo package.json changes
|
|
||||||
#
|
|
||||||
# Prerequisites:
|
|
||||||
# cd ../learning_ai_common_plat && pnpm build
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
# docker-prep.sh — Prep ChronoMind Docker consumers via the shared common-plat prep-consumer script.
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/docker-prep.sh # prep backend + web for docker build
|
||||||
|
# ./scripts/docker-prep.sh --restore # restore package.json changes and remove .docker-deps
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
COMMON_PLAT="${REPO_ROOT}/../learning_ai_common_plat"
|
COMMON_PLAT="${REPO_ROOT}/../learning_ai_common_plat"
|
||||||
PREP_SCRIPT="${COMMON_PLAT}/scripts/prep-consumer.sh"
|
PREP_SCRIPT="${COMMON_PLAT}/scripts/prep-consumer.sh"
|
||||||
|
|
||||||
if [ ! -f "$PREP_SCRIPT" ]; then
|
if [[ ! -f "$PREP_SCRIPT" ]]; then
|
||||||
echo "❌ Cannot find prep-consumer.sh at $PREP_SCRIPT"
|
echo "❌ Cannot find prep-consumer.sh at $PREP_SCRIPT"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Consumers in this repo that use file: refs to @bytelyst/* packages
|
CONSUMERS=(backend web)
|
||||||
CONSUMERS=(web)
|
|
||||||
|
|
||||||
MODE="${1:-}"
|
MODE="${1:-}"
|
||||||
|
|
||||||
for consumer in "${CONSUMERS[@]}"; do
|
for consumer in "${CONSUMERS[@]}"; do
|
||||||
TARGET="${REPO_ROOT}/${consumer}"
|
TARGET="${REPO_ROOT}/${consumer}"
|
||||||
if [ ! -d "$TARGET" ]; then
|
if [[ ! -d "$TARGET" ]]; then
|
||||||
echo "⚠️ Skipping ${consumer} — directory not found"
|
echo "⚠️ Skipping ${consumer} — directory not found"
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
@ -41,5 +35,6 @@ done
|
|||||||
|
|
||||||
if [[ "$MODE" != "--restore" ]]; then
|
if [[ "$MODE" != "--restore" ]]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "✅ Docker prep complete. Restore with: ./scripts/docker-prep.sh --restore"
|
echo "✅ Docker prep complete. Run 'docker build' now, then restore with:"
|
||||||
|
echo " ./scripts/docker-prep.sh --restore"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -1,24 +1,30 @@
|
|||||||
# Pre-requisite: run ./scripts/docker-prep.sh to pack @bytelyst/* tarballs
|
# Pre-requisite: run ./scripts/docker-prep.sh to pack @bytelyst/* tarballs
|
||||||
FROM node:22-alpine AS builder
|
# ── Stage 1: Build ────────────────────────────────────
|
||||||
WORKDIR /app
|
FROM node:22-slim AS builder
|
||||||
|
WORKDIR /app/web
|
||||||
|
RUN npm config set strict-ssl false
|
||||||
|
COPY web/package.json ./package.json
|
||||||
|
COPY web/.docker-deps/ ./.docker-deps/
|
||||||
|
RUN npm install --legacy-peer-deps
|
||||||
|
|
||||||
COPY package.json package-lock.json ./
|
COPY web/src/ ./src/
|
||||||
COPY .tarballs/ ./.tarballs/
|
COPY web/tsconfig.json web/next.config.ts web/postcss.config.mjs ./
|
||||||
RUN npm ci
|
COPY web/public/ ./public/
|
||||||
|
COPY shared/ ../shared/
|
||||||
COPY . .
|
|
||||||
|
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
ENV NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
FROM node:22-alpine
|
# ── Stage 2: Runtime ──────────────────────────────────
|
||||||
|
FROM node:22-slim
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
COPY --from=builder /app/.next/standalone ./
|
COPY --from=builder /app/web/.next/standalone ./
|
||||||
COPY --from=builder /app/.next/static ./.next/static
|
COPY --from=builder /app/web/.next/static ./.next/static
|
||||||
COPY --from=builder /app/public ./public 2>/dev/null || true
|
COPY --from=builder /app/web/public ./public
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
CMD ["node", "server.js"]
|
CMD ["node", "server.js"]
|
||||||
|
|||||||
@ -35,6 +35,20 @@ const securityHeaders = [
|
|||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
...(process.env.VERCEL ? {} : { output: 'standalone' }),
|
...(process.env.VERCEL ? {} : { output: 'standalone' }),
|
||||||
|
transpilePackages: [
|
||||||
|
"@bytelyst/api-client",
|
||||||
|
"@bytelyst/auth-client",
|
||||||
|
"@bytelyst/diagnostics-client",
|
||||||
|
"@bytelyst/feature-flag-client",
|
||||||
|
"@bytelyst/react-auth",
|
||||||
|
"@bytelyst/subscription-client",
|
||||||
|
"@bytelyst/sync",
|
||||||
|
"@bytelyst/telemetry-client",
|
||||||
|
],
|
||||||
|
webpack: (config) => {
|
||||||
|
config.resolve.symlinks = true;
|
||||||
|
return config;
|
||||||
|
},
|
||||||
async headers() {
|
async headers() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
9986
web/package-lock.json
generated
9986
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
|||||||
"name": "web",
|
"name": "web",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"packageManager": "pnpm@10.6.5",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --webpack",
|
"dev": "next dev --webpack",
|
||||||
"build": "next build --webpack",
|
"build": "next build --webpack",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user