Files

115 lines
4.6 KiB
Markdown

# Development containers (M1)
Four-service Docker Compose stack: nginx, unprivileged PHP-FPM, PostgreSQL and
an assets container for Tailwind CSS builds. The application layer (Slim 4,
PHP-DI, Monolog) is wired, but there is no catalog schema, migration runner or
asset pipeline beyond Tailwind. Do not expose this stack to the Internet.
## Prerequisites
- Docker Engine/Desktop with Linux containers and Docker Compose v2+.
- No host PHP, Composer or Node is required.
## First start
From the repository root, copy `.env.example` to `.env` and edit
`MESHVAULT_DB_PASSWORD` to a private, nonempty value. Never commit `.env` or print
expanded Compose configuration in shared logs; use `docker compose config --quiet`.
Create a **new dedicated** `library` directory (`mkdir library`). Do not use an
existing collection. On Linux, give container UID/GID 33 ownership of that new
empty directory, for example `sudo chown 33:33 ./library` and
`sudo chmod 750 ./library`. Alternatively, after building, use the narrowly scoped
one-off command below **only for this new empty directory**:
```sh
docker compose build app
docker compose run --rm --no-deps --user root app chown 33:33 /var/lib/meshvault/library
docker compose config --quiet
docker compose up -d --wait
```
Also ensure `public/build` is writable by the assets container user (`node`, UID
1000). On Linux, run:
```sh
mkdir -p public/build
chown 1000:1000 public/build
```
Docker Desktop bind permissions differ; verify writability using the runtime
identity rather than assuming host chmod works. The stack never automatically
creates or changes ownership of a configured library directory.
## Task wrappers
Use `dev.sh` (POSIX) or `dev.ps1` (PowerShell) from the repository root. They are
independent of your current working directory and propagate exit codes.
```sh
./dev.sh up # build and start services
./dev.sh down # stop services (volume removal is forbidden)
./dev.sh test # run composer test inside the app container
./dev.sh lint # run composer lint inside the app container
./dev.sh assets # build minified CSS inside the assets container
./dev.sh watch # start Tailwind watch inside the assets container
./dev.sh migrate # run database migrations (M2 #12)
./dev.sh seed # seed default reference data (M2 #12)
```
`down --volumes` and `down -v` are blocked by the wrapper. Never remove the named
`pgdata` volume or the library bind.
## Asset builds
Assets are built inside the `assets` service using a locked `package-lock.json`.
The generated `public/build/app.css` is served statically by nginx.
```sh
./dev.sh assets
```
Watch mode rebuilds on template changes:
```sh
./dev.sh watch
```
## Verification
Open http://127.0.0.1:8090/ for the landing page. `docker compose exec app id`
should report UID/GID 33. Check a disposable library write without becoming root:
```sh
docker compose exec app php -r '$p = getenv("MESHVAULT_LIBRARY_DIR") . "/write-check"; if (file_put_contents($p, "ok") === false) { exit(1); } unlink($p);'
```
`down` preserves the named `pgdata` volume and library bind. Changing database
credentials in `.env` does not change credentials in an initialized PostgreSQL
volume. Back up data before upgrades.
## Settings and boundaries
`.env.example` documents every current setting: Compose project, HTTP host/port,
DB name/user/password, host library path and absolute container library path.
The container library path must stay outside `/var/www/html` and must not overlap
system paths. The only required non-default value is the database password.
The default project is `meshvault-m1`; HTTP binds localhost:8090. Only nginx has a
published port. PostgreSQL readiness gates app startup. FPM itself runs as
`www-data`, not just its workers. nginx mounts only `public/` and executes only
`/index.php`; source, credentials and library are not web mounts.
Source mounts are explicit and read-only. No host `vendor` or `node_modules` is
mounted; dependencies are installed inside images from lockfiles. No Docker socket
is mounted. Startup configuration validation is provided by the entrypoint script.
Image branches: PHP 8.3 FPM Bookworm (security support to December 2027), PostgreSQL
17 Bookworm (support to November 2029), nginx 1.30 Alpine (stable), Node 24
Bookworm slim (LTS). Tags are versioned but move with patch updates, not digest
locks. PHP 8.3 compatibility is retained.
Remote verification uses only `/home/keith/Projects/MeshVault` after confirming
HOME, explicit project `meshvault-m1`, and an explicit source-only copy manifest.
Access from another machine via `ssh -L 8090:127.0.0.1:8090 keith@192.168.2.23`.
Never attach original collections or change unrelated services.