diff --git a/CLAUDE.md b/CLAUDE.md index d5137ee3..02f1ea8c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -13,34 +13,39 @@ Plack/PSGI with a JSON::RPC::Dispatcher API layer. ## Development environment -Docker Compose is the supported way to run this stack; there is no cpanfile/Makefile.PL — Perl dependencies are pinned -as `cpanm --notest ` lines directly in `docker/build-server/Dockerfile` (Perl 5.24, ~100 modules: Moose, -DBIx::Class, Plack, Test::Class::Moose, Test::Most, GD::SecurityImage, etc.). Treat that Dockerfile as the dependency -source of truth. - -Setup: - -1. `npm run dev:build` -1. `npm run dev:up` - -Services defined in `docker-compose.yml` (dev; `docker-compose.deployed.yml` is the prod variant): - -- `mysql` — mysql:5.7, root password `lacuna`, port 3306 -- `memcached` — session/cache store -- `beanstalk` (+ `-console` on 2080) — job queue -- `phpmyadmin` — port 8888 -- `nginx` — port 80→3000, serves static assets/app and proxies to server + v2-api -- `v2-api` — newer TypeScript API, port 5999 -- `server` — the Perl app, runs `bin/startdev.sh`, port 3050:5000 -- `app` / `super-ui` — build the frontend submodules -- `server-{building,ship,captcha}-scheduler` — Perl scheduler processes -- `server-script-scheduler` — ofelia-based cron, driven by `docker/server/schedule.ini` - -Inside `server`, `bin/startdev.sh` `plackup --env development --app lacuna.psgi`. Production instead uses -`start_server -- starman --workers 7 ... lacuna.psgi` (see `bin/start_lacuna.sh`). - -`bin/setup/server/*.sh` and `bin/setup/install-pm.sh` are legacy CentOS-era bare-metal setup scripts predating Docker — -historical/reference only, not the recommended path. +Docker Compose is the supported way to run this stack. Perl dependencies are managed with Carton: `cpanfile` lists them +and the committed `cpanfile.snapshot` pins them; the root `Dockerfile` (perl:5.40) runs `carton install --deployment` +into `./local`. + +Setup (from the repo root; `npm` only provides the prettier scripts in `package.json`): + +1. `git submodule update --init` +1. `cp etc/lacuna.example.conf etc/lacuna.conf` (gitignored; the example already points at the compose service names) +1. `export LACUNA_MYSQL_ROOT_PASSWORD=lacuna CONTAINER_REGISTRY_URL=`: compose refuses to start without both. + `v2-api` pulls from a private registry; without access, set any value and start services by name. +1. `docker compose build server` +1. `docker compose up -d mysql memcached beanstalk` +1. On Linux, `./data/memcached` is created root-owned by the daemon and the `memcached` image runs as uid 11211, so it + crash-loops with `failed to open file for mmap: Permission denied` and the tests fail. + `sudo chmod 777 data/memcached`, then `docker restart memcached`. +1. `docker exec mysql mysql -uroot -p$LACUNA_MYSQL_ROOT_PASSWORD -e 'create database lacuna'` +1. `docker compose run --rm --no-deps -w /home/lacuna/server/bin/setup server perl init_lacuna.pl` +1. `docker compose up -d --no-deps server` (healthy once `/starman_ping` answers) + +Services defined in `docker-compose.yml` (no ports are published to the host): + +- `mysql`: mysql:5.5, root password from `LACUNA_MYSQL_ROOT_PASSWORD`, data in `./data/mysql` +- `memcached`: session/cache store, persisted to `./data/memcached` +- `beanstalk` (+ `beanstalk-console`): job queue +- `phpmyadmin` +- `v2-api`: newer TypeScript API, image `${CONTAINER_REGISTRY_URL}/tlecommunity/v2-api` +- `server`: the Perl app, runs `bin/start_lacuna.sh` +- `server-{building,ship,captcha}-scheduler`: Perl scheduler processes +- `server-script-scheduler`: ofelia-based cron, mounts `./schedule.ini` + +Inside `server`, `bin/start_lacuna.sh` runs `bin/migrate_db.pl` and then +`start_server -- starman --workers 7 --preload-app lacuna.psgi`, so restart the container after changing `lib/`. +`bin/startdev.sh` is the plackup alternative (`plackup --env development --app lacuna.psgi`). ## Testing @@ -52,11 +57,12 @@ base class). They are **integration tests that hit a live server over HTTP**, no `Lacuna->config->get('server_url')` (which points at the deployed server). So the suite must run inside `server` with the compose stack up. -- Full suite: `npm run dev:run -- server ./run_tests.sh` -- Single file: `npm run dev:run -- server ./run_tests.sh t/010_Empire.t` -- `bin/run_tests.sh` just sets `LACUNA_TEST_SERVER_URL`, `cd`s to the server root and runs `prove -Ilib -It` (the `-It` - makes `use TestHelper` resolve regardless of each file's own `use lib` line; note that the container's workdir is - `bin/` so you don't need to have bin/ in your commands or set the working directory yourself). +- Single file: `docker exec server prove -Ilib -It t/010_Empire.t` (the container's workdir is the server root) +- Full suite: `docker exec -e LACUNA_TEST_SERVER_URL=http://localhost:5000/ server bash bin/run_tests.sh` +- `bin/run_tests.sh` (not executable; run it with `bash`) sets `LACUNA_TEST_SERVER_URL`, `cd`s to the server root and + runs `prove -Ilib -It` (the `-It` makes `use TestHelper` resolve regardless of each file's own `use lib` line). Its + default URL is `http://server:5000/`, which makes the server see the container's network address instead of 127.0.0.1, + so `t/010_Empire.t` fails its captcha-seeded empire creation; override it as above. - Test locations: `t/*.t` (numbered, e.g. `t/010_Empire.t`), `t/bugs/*.t` (regression tests, e.g. `t/bugs/0003_PurchaseTooManyShips.t`), `t/long_running/` (excluded from the default `bin/run_tests.sh` run — slow), `t/middleware/` @@ -115,7 +121,7 @@ in that state (predates this tooling, or was just restored from a backup) has to human who has confirmed what version its schema actually matches: `perl bin/stamp_db_version.pl ` — this only creates the version-tracking table and records that one row, it never touches any other table. -To add a new building, follow the checklist in `info/add_a_building.txt` (DB::Result class, entry in +To add a new building, follow the checklist in `info/add-a-building.md` (DB::Result class, entry in `Lacuna::DB::Result::Building` class types, RPC class, entry in `bin/lacuna.psgi`, `Lacuna::DB::Result::Medals`, images, and — if buildable — `Lacuna::Constants::BUILDABLE_CLASSES`; plus `SPACE_STATION_MODULES` if it's a station module).