Monorepo layout
ulams is one git repository with three applications (api, admin, front) plus documentation
and root tooling. The decision and its history are in
ADR 0001 (monorepo with vendored packages) and
ADR 0005 (Turborepo and Yarn workspaces).
Layout
Section titled “Layout”Directoryapi/ Laravel API (
apiworkspace: scripts only)Directoryapp/ application code: kernels, providers, a few controllers
- …
Directoryconfig/ Laravel config;
app.phpregisters every package provider- …
Directorypackages/ vendored domain packages, one directory each, see API packages
- …
Directoryh5p/ H5P service, Node, GPL (
api-h5pworkspace)- …
Directorypdf/ PDF renderer, Node, pdfme (
api-pdfworkspace)- …
Directorydocker/ PHP base image, Caddyfile, supervisor configs, env scripts
- …
Directorydocs/ API docs: multidomain, content origin, env variables, retroactive ADRs
- …
Directorytests/ application tests; package tests live in
packages/<name>/tests- …
- docker-compose.yml development stack
- init.sh, queue.sh, scheduler.sh, broadcast.sh, domains.sh container processes
Directoryadmin/ admin panel, umi/max (
adminworkspace)Directoryconfig/ routes, umi config,
@ulams/*aliases- …
Directorysrc/
Directorylib/ vendored
gift-pegjsandmarkdown-editor- …
Directoryfront/
Directorysrc/ legacy React learner app (
frontworkspace)Directorylib/ shared libraries: components, sdk, ts-models, scorm-player, tenant, demo
- …
Directoryweb/ reference frontend, Astro SSR (
@ulams/web)- …
Directorysdk/ framework-free API client (
@ulams/sdk)- …
Directoryui/ UI catalogue and renderer (
@ulams/ui)- …
Directorydocs-site/ this documentation site (
@ulams/docs)- …
Directorydocs/
- ROADMAP-PROMPT.md spec
- ROADMAP-TODO.md progress tracker
Directorydecisions/ project-wide ADRs
- …
Directoryplans/ phase plans
- …
- package.json root workspaces and scripts
- turbo.json task graph
- yarn.lock one lockfile for every workspace
Workspaces
Section titled “Workspaces”Yarn 1 workspaces (packageManager: yarn@1.22.22, Node >=22.12) with a single root yarn.lock.
The root package.json lists:
| Path | Package name | What |
|---|---|---|
admin |
admin |
Admin panel (umi/max, React, Ant Design Pro) |
front |
front |
Legacy learner app (React 18, Vite) |
front/sdk |
@ulams/sdk |
TypeScript API client, fetch only |
front/ui |
@ulams/ui |
Component catalogue, renderer, web components, themes |
front/web |
@ulams/web |
Reference frontend (Astro 5 SSR) |
front/docs-site |
@ulams/docs |
This site (Astro Starlight) |
api |
api |
Scripts only (Docker, artisan, phpunit), so the API joins the task graph |
api/h5p |
api-h5p |
H5P service |
api/pdf |
api-pdf |
PDF renderer |
A few packages are excluded from hoisting (nohoist) because the legacy front and the H5P service
need their own copies.
Turborepo tasks
Section titled “Turborepo tasks”turbo.json defines dev, build, lint, typecheck, test and test:integration. Notable
details:
buildoutputsdist/**;testoutputscoverage/**;devandtest:integrationare never cached.admin#build,admin#typecheckandadmin#testaddfront/src/lib/**to their inputs, because the admin imports libraries from there. A change in a shared library invalidates the admin cache.- Build-time environment variables that affect the output are declared (
VITE_*,REACT_APP_*,SENTRY_*,BASE_PATH,UMI_ENV), so they are part of the cache key.
Root scripts wrap the common filters:
yarn dev # admin (:8000) and legacy front (:3000)yarn dev:web # reference frontend (:4321)yarn dev:docs # this siteyarn dev:api # docker compose -f api/docker-compose.yml up -dyarn build # turbo run buildyarn lint && yarn typecheckyarn test # JS tests of admin, front, api-h5p, api-pdf, sdk, ui, webyarn test:api # PHP tests (yarn workspace api test)Running the stack and the test suites is covered in Local development and Testing.
Where shared code lives
Section titled “Where shared code lives”| Code | Location | Imported as | Used by |
|---|---|---|---|
| PHP domain packages | api/packages/<name> |
Ulams\<Name>\ (PSR-4 in api/composer.json) |
API |
| API client for new apps | front/sdk |
@ulams/sdk (workspace) |
front/web, front/ui |
| UI catalogue | front/ui |
@ulams/ui (workspace) |
front/web |
| Legacy component library | front/src/lib/components |
@ulams/components (path alias) |
legacy front |
| Legacy API client and React context | front/src/lib/sdk |
@ulams/sdk (path alias, a different package from front/sdk) |
legacy front |
| API types | front/src/lib/ts-models |
global declarations (models.d.ts, included through src) |
legacy front |
| SCORM runtime | front/src/lib/scorm-player |
@ulams/scorm-player |
legacy front, admin |
| Tenant host rules | front/src/lib/tenant/resolveApiUrl.ts |
@ulams/tenant; re-exported by @ulams/sdk/tenant |
legacy front, admin, front/web |
| Demo-mode helpers | front/src/lib/demo/demoMode.ts |
@ulams/demo |
legacy front, admin |
| GIFT parser, Markdown editor | admin/src/lib |
@ulams/gift-pegjs, @ulams/markdown-editor |
admin |
The admin aliases are in admin/config/config.ts and admin/tsconfig.json; keep both in sync.
Vendored code and provenance
Section titled “Vendored code and provenance”Every former escolalms/* composer package is plain source in api/packages/ with no
composer.json of its own. The provenance table (upstream repository, version, commit) is in
api/packages/README.md and
the imported versions are in api/packages/versions.json. The JS libraries in front/src/lib and
admin/src/lib keep a README with their origin. Adding or changing an API package is described in
API packages.