Repository layout
tohe-play/├── AGENTS.md / CLAUDE.md Entry point for AI agents (short; points here)├── docs/ This documentation — the specification├── plans/ Plan spaces: intent worked out with the owner before it becomes spec (not published)├── apps/│ ├── hub/ React PWA: catalog, launcher, profiles, local-first storage│ ├── console/ The operator's console, on a host of its own (ADR 0027, 0042)│ ├── web/ Astro: the public pages (vi), built into the hub image and served at its root (ADR 0042)│ └── docs/ Astro + Starlight: renders docs/ at the root of the docs host├── services/│ └── api/ .NET 10 solution (Tohe.slnx): src/Tohe.Api, tests/Tohe.Api.Tests, openapi/├── packages/│ ├── contract/ Game Contract v1: Zod schemas, JSON Schema output, game CSP│ ├── game-sdk/ Game side (dependency-free) + host side (/host) of the contract│ ├── game-kit/ Shared game building blocks: Phaser setup, sfx, haptics, juice, overlay (ADR 0012)│ └── design-tokens/ Light/dark colour tokens + the shared theme choice, for hub, public pages, docs and kit (ADR 0013)├── games/│ └── <id>/ One folder per game; folder name = game id├── tools/│ ├── conformance/ Checks a built game against the contract (Playwright)│ ├── games-host/ Assembles games into .out/games + serves the local games origin│ ├── e2e/ End-to-end smoke test against a running stack│ └── codegen/ Generators that need TypeScript 5's compiler API (API types)├── deploy/│ ├── docker/ Dockerfiles and Caddyfiles (one set of images for every environment, ADR 0021)│ ├── helm/tohe/ The Helm chart: self-hosting and production (ADR 0021)│ └── uat/ UAT deploy and backup scripts (ADR 0010)├── compose.yaml Local stack└── .claude/skills/ Agent skills: new-game, new-adr, verifyPackage rules
| Package | May depend on | Must not |
|---|---|---|
@tohe/contract | zod | anything in this repo |
@tohe/game-sdk (game side) | types from @tohe/contract only | runtime dependencies of any kind |
@tohe/game-sdk/host | @tohe/contract | — |
@tohe/game-kit | @tohe/game-sdk (types), @tohe/design-tokens, Phaser (optional peer, ./phaser entry only) | the hub, the API |
@tohe/design-tokens | nothing (CSS, a parser, the theme choice) | anything in this repo |
games/* | @tohe/game-sdk, @tohe/game-kit, @tohe/design-tokens, any library that fits the game | the hub, the API, other games, network access |
apps/hub | contract, SDK host, design tokens, generated API types | game code |
apps/console | design tokens, the admin API’s generated types, @tohe/routes in its tests | the hub, game code |
services/api | NuGet packages in Directory.Packages.props | game code |
TypeScript packages inside the monorepo export their source ("exports": "./src/index.ts"); bundlers and
Node 24 (type stripping) consume it directly, so there is no build step between packages. The SDK additionally
builds dist/tohe-game-sdk.iife.js for games without a bundler.
Generated, committed files
| File | Generated by | Checked by |
|---|---|---|
packages/contract/schema/*.json | pnpm --filter @tohe/contract build | CI fails on drift |
services/api/openapi/tohe-api.json, tohe-api_admin.json | dotnet build (build-time OpenAPI; the second is the admin API’s) | CI fails on drift |
apps/hub/src/api/schema.gen.ts, apps/console/src/api/schema.gen.ts | pnpm --filter @tohe/hub generate:api (both) | CI fails on drift |
apps/hub/public/*.png | pnpm --filter @tohe/hub generate:icons | — |
services/api/src/Tohe.Api/Infrastructure/Database/Migrations/* | dotnet ef migrations add <Name> | tests apply them to a real PostgreSQL |