Skip to content

Commit 252c91c

Browse files
CoderCococlaude
andauthored
build(workspaces): promote repo root to npm workspace root (#53)
## Summary Restructure the npm workspace tree to be rooted at the repository root instead of under `app/`, simplifying dependency management and build workflows across the entire project. ## Key Changes - **Workspace root relocation**: Moved workspace configuration from `app/package.json` to a new root `package.json`, with workspaces now defined as `["app", "app/packages/*", "scripts"]` - **Root-level npm commands**: Added convenience scripts at the root level (e.g., `npm run app:dev`, `npm run app:build`) that delegate to workspace-specific commands, eliminating the need to `cd app` before running tasks - **Dockerfile updates**: - Changed `WORKDIR` from `/app` to `/workspace` to match the new structure - Updated all `COPY` commands to reference the root `package.json` and adjust paths accordingly - Added stub `scripts/package.json` to prevent npm from installing maintainer-only dev tools in production - Added final `WORKDIR /workspace/app` to preserve existing behavior for `ConfigService` path probing - **CI/CD workflow updates**: Removed `working-directory: app` defaults and updated cache paths to use root-level `package-lock.json`; updated lint and test commands to use new root-level scripts - **Documentation updates**: - Updated `CLAUDE.md` with new command patterns (e.g., `npm run app:dev` instead of `cd app && npm run dev`) - Updated submodule setup guide to use the new workspace structure - Updated `docker-compose.yml` volume mounts to reflect `/workspace` paths - **Setup script**: Updated `setup.sh` to run `npm ci` from repo root instead of `app/` directory ## Implementation Details The restructuring maintains backward compatibility by: - Keeping the `app/` directory structure intact with its own `package.json` (now without workspace declarations) - Using root-level convenience scripts that target specific workspaces with `-w` flag - Preserving the final working directory in Docker as `/workspace/app` to ensure existing path-based logic continues to work - Creating a stub `scripts/package.json` to prevent unnecessary dependencies in the production image while still allowing the workspace to be referenced This change simplifies the mental model of the project structure and reduces friction when running commands from the repository root. https://claude.ai/code/session_01BfCUaJBR6wTmdH2ET8oov4 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent a9d3b3a commit 252c91c

12 files changed

Lines changed: 10855 additions & 644 deletions

File tree

.github/workflows/lint.yml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,18 @@ permissions:
1111
jobs:
1212
eslint:
1313
runs-on: ubuntu-latest
14-
defaults:
15-
run:
16-
working-directory: app
1714
steps:
1815
- uses: actions/checkout@v5
1916

2017
- uses: actions/setup-node@v5
2118
with:
2219
node-version: '24'
2320
cache: npm
24-
cache-dependency-path: app/package-lock.json
21+
cache-dependency-path: package-lock.json
2522

2623
- run: npm ci
2724

28-
- run: npm run lint
25+
- run: npm run app:lint
2926

3027
tflint:
3128
runs-on: ubuntu-latest

.github/workflows/test.yml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,15 @@ on:
88
jobs:
99
test:
1010
runs-on: ubuntu-latest
11-
defaults:
12-
run:
13-
working-directory: app
1411
steps:
1512
- uses: actions/checkout@v5
1613

1714
- uses: actions/setup-node@v5
1815
with:
1916
node-version: '24'
2017
cache: npm
21-
cache-dependency-path: app/package-lock.json
18+
cache-dependency-path: package-lock.json
2219

2320
- run: npm ci
2421

25-
- run: npm test
22+
- run: npm run app:test

CLAUDE.md

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,44 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Common Commands
66

7-
The management app is a TypeScript **npm-workspaces** monorepo under `app/`. Dependencies are installed once at the workspace root. The workspaces are:
7+
The repo uses a single **npm-workspaces** tree rooted at the repo root. Workspaces are:
88

99
- `@gsd/shared` — types, `canRun`, sanitizers, status formatter, command descriptors, DynamoDB + Secrets Manager helpers (used by both the server and the Lambdas).
1010
- `@gsd/server` — Nest.js management API.
1111
- `@gsd/web` — React + Vite client.
1212
- `@gsd/lambda-interactions`, `@gsd/lambda-followup`, `@gsd/lambda-update-dns`, `@gsd/lambda-watchdog` — four Lambda packages, each bundled to a single `dist/handler.cjs` by esbuild.
13+
- `@gsd/scripts` — maintainer helper scripts (`init-parent.ts` scaffolder).
1314

1415
```bash
15-
# Install all workspaces in one go
16-
cd app && npm install
16+
# Install all workspaces in one go (run from repo root)
17+
npm install
1718

1819
# Run the dev servers (Nest on 3001, Vite on 5173 with /api proxy)
19-
cd app && npm run dev
20+
npm run app:dev
2021

2122
# Production build (shared → server → web)
22-
cd app && npm run build && npm start # http://localhost:3001
23+
npm run app:build && npm run app:start # http://localhost:3001
2324

2425
# Build all Lambda bundles (required before `terraform apply`)
25-
cd app && npm run build:lambdas
26+
npm run app:build:lambdas
27+
28+
# Unit tests (vitest + aws-sdk-client-mock) — discovered across every workspace
29+
npm run app:test # one-off run
30+
npm run app:test:watch # watch mode
31+
32+
# Lint / autofix
33+
npm run app:lint
34+
npm run app:lint:fix
35+
36+
# Run the scaffolder script
37+
npm run scripts:init-parent
2638

2739
# Run the app in Docker (mounts ./terraform ro, ./app/server_config.json, ~/.aws)
2840
docker compose up --build # http://localhost:5000
2941

3042
# Terraform (all infra lives under terraform/). NOTE: terraform apply reads
3143
# the Lambda bundles from app/packages/lambda/*/dist/handler.cjs — run
32-
# `npm run build:lambdas` first or the archive_file data sources will fail.
44+
# `npm run app:build:lambdas` first or the archive_file data sources will fail.
3345
cd terraform
3446
terraform init
3547
terraform plan
@@ -39,13 +51,9 @@ terraform destroy
3951
# First-time environment bootstrap (installs terraform + aws CLI if missing,
4052
# runs npm ci, builds Lambdas, runs terraform init)
4153
./setup.sh
42-
43-
# Unit tests (vitest + aws-sdk-client-mock) — discovered across every workspace
44-
cd app && npm test # one-off run
45-
cd app && npm run test:watch # watch mode
4654
```
4755

48-
ESLint (flat config) lives at `app/eslint.config.js` using `@eslint/js` + `typescript-eslint` recommended presets, plus `eslint-plugin-react` and `eslint-plugin-react-hooks` recommended for the web package. Run `npm run lint` (or `npm run lint:fix`) from `app/`.
56+
ESLint (flat config) lives at `app/eslint.config.js` using `@eslint/js` + `typescript-eslint` recommended presets, plus `eslint-plugin-react` and `eslint-plugin-react-hooks` recommended for the web package. Run `npm run app:lint` (or `npm run app:lint:fix`) from the repo root.
4957

5058
Terraform linting uses [tflint](https://github.com/terraform-linters/tflint) with its `recommended` preset and the AWS ruleset plugin. Config lives at `terraform/.tflint.hcl`. Run `tflint --init` once to install the plugin, then `tflint` from `terraform/`. `terraform fmt -check -recursive` and `terraform validate` cover formatting and syntax.
5159

Dockerfile

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11
FROM node:20-slim
22

3-
WORKDIR /app
4-
5-
# Install dependencies first (layer cache). npm ci uses the workspace root's
6-
# package.json + lockfile, which installs every workspace package's deps.
7-
COPY app/package.json app/package-lock.json* ./
8-
COPY app/packages/shared/package.json packages/shared/
9-
COPY app/packages/server/package.json packages/server/
10-
COPY app/packages/web/package.json packages/web/
11-
COPY app/packages/lambda/interactions/package.json packages/lambda/interactions/
12-
COPY app/packages/lambda/followup/package.json packages/lambda/followup/
13-
COPY app/packages/lambda/update-dns/package.json packages/lambda/update-dns/
14-
COPY app/packages/lambda/watchdog/package.json packages/lambda/watchdog/
3+
# Workspace root lives at /workspace (= repo root). All npm workspace
4+
# members (app, app/packages/*, scripts) are installed from here.
5+
WORKDIR /workspace
6+
7+
# Copy root manifest + lockfile first for layer-cache-efficient installs.
8+
COPY package.json package-lock.json ./
9+
10+
# Copy every workspace member's package.json so npm ci can resolve them.
11+
COPY app/package.json app/
12+
COPY app/packages/shared/package.json app/packages/shared/
13+
COPY app/packages/server/package.json app/packages/server/
14+
COPY app/packages/web/package.json app/packages/web/
15+
COPY app/packages/lambda/interactions/package.json app/packages/lambda/interactions/
16+
COPY app/packages/lambda/followup/package.json app/packages/lambda/followup/
17+
COPY app/packages/lambda/update-dns/package.json app/packages/lambda/update-dns/
18+
COPY app/packages/lambda/watchdog/package.json app/packages/lambda/watchdog/
19+
COPY app/packages/lambda/efs-seeder/package.json app/packages/lambda/efs-seeder/
20+
21+
COPY scripts/package.json scripts/
22+
1523
RUN npm ci --ignore-scripts
1624

1725
# Copy source and build the server + web bundle for the management app. The
1826
# Lambda packages are NOT built here — they are bundled and deployed by
1927
# `terraform apply` (see `setup.sh`) and have no place inside the container.
20-
COPY app/ .
21-
RUN npm run build
28+
COPY app/ app/
29+
RUN npm run build -w game-server-manager
30+
31+
# Switch to the app directory so ConfigService path probing and process.cwd()
32+
# behave the same as in the previous single-WORKDIR setup.
33+
WORKDIR /workspace/app
2234

2335
EXPOSE 3001
2436

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ $EDITOR terraform/terraform.tfvars # game_servers, hosted_zone_name, ...
6262
cd terraform && terraform apply
6363

6464
# 4a. Run the management app in dev mode
65-
cd ../app && npm run dev
65+
cd .. && npm run app:dev
6666
# http://localhost:5173 (Nest on :3001, Vite proxy)
6767

6868
# 4b. …or in Docker (production mode — requires a bearer token)

app/package.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@
33
"version": "1.0.0",
44
"private": true,
55
"type": "module",
6-
"workspaces": [
7-
"packages/shared",
8-
"packages/server",
9-
"packages/web",
10-
"packages/lambda/*"
11-
],
126
"scripts": {
137
"predev": "node scripts/embed-tfstate.mjs",
148
"dev": "concurrently -n server,client -c cyan,magenta \"npm run dev -w @gsd/server\" \"npm run dev -w @gsd/web\"",

docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ services:
55
- "5000:3001"
66
volumes:
77
# Makes terraform.tfstate readable by the app
8-
- ./terraform:/app/terraform:ro
8+
- ./terraform:/workspace/terraform:ro
99
# Persists server_config.json across container restarts.
1010
# NOTE: the host file must exist before `docker compose up` — create it with
1111
# `touch app/server_config.json` on first run. With
@@ -15,7 +15,7 @@ services:
1515
# default short-syntax mounts would otherwise cause.
1616
- type: bind
1717
source: ./app/server_config.json
18-
target: /app/server_config.json
18+
target: /workspace/app/server_config.json
1919
bind:
2020
create_host_path: false
2121
# AWS credentials — remove if using env vars instead

docs/docs/guides/submodule.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,9 @@ cd your-private-games
8686
# 2. Add the submodule.
8787
git submodule add https://github.com/CoderCoco/game-server-deploy.git
8888

89-
# 3. Install scaffolder deps and run it from the parent repo root.
90-
(cd game-server-deploy/scripts && npm install)
91-
npx --prefix game-server-deploy/scripts tsx \
92-
game-server-deploy/scripts/init-parent.ts
89+
# 3. Install all deps and run the scaffolder.
90+
(cd game-server-deploy && npm install)
91+
(cd game-server-deploy && npm run scripts:init-parent)
9392
```
9493

9594
The script prompts for project name, AWS region, hosted zone, and

0 commit comments

Comments
 (0)