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:
saravanakumardb1 2026-03-22 19:11:01 -07:00
parent ab400fbb6a
commit 582936ad65
15 changed files with 12844 additions and 12856 deletions

9
.dockerignore Normal file
View File

@ -0,0 +1,9 @@
node_modules
backend/node_modules
web/node_modules
backend/dist
web/.next
*.log
.env
.env.*
pnpm-lock.yaml

View File

@ -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
View File

@ -0,0 +1,7 @@
node_modules
dist
.next
*.log
.env
.env.*
.DS_Store

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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

File diff suppressed because it is too large Load Diff

4
pnpm-workspace.yaml Normal file
View File

@ -0,0 +1,4 @@
packages:
- backend
- web
- ../learning_ai_common_plat/packages/*

View File

@ -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

View File

@ -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"]

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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