build: M1 Dockerized development stack with PHP skeleton, config/logging, Tailwind assets, and wrappers

Implements MeshVault M1 (issues #6–11):

- Four-service Docker Compose stack (nginx, PHP-FPM 8.3, PostgreSQL 17, Node assets)
- Slim 4 + PHP-DI routing with escaped PHP views and production/dev error handling
- Immutable validated AppConfig with redacted diagnostics
- JSON stdout Monolog logging with job-scoped context
- Tailwind CSS v4 deterministic locked builds with template scanning
- POSIX and PowerShell dev wrappers (up/down/test/lint/assets/watch)
- Startup config validation fails before FPM serves as unprivileged www-data
- migrate/seed explicitly unavailable until M2 (#12); #10 remains open

Verified via clean-start acceptance on remote host (keith@192.168.2.23).
This commit is contained in:
Keith Solomon committed 2026-10-11 16:45:45 -05:00
1 parent c2747a5762
commit d3e8cf8fae
39 files changed
+5291 -38

No files matched your search

+51 -15
View File
@@ -3,10 +3,11 @@
MeshVault is a self-hosted 3D model library being built as a Docker service.
It catalogs logical models containing STL parts, images and supplementary documents.
**Status:** M0 foundations only. There is no runnable web application, database
schema or Docker stack yet. Installation and a verified application quick start
are deliverables of [M1](https://git.keithsolomon.net/keith/MeshVault/milestones).
Do not deploy this scaffold as a service.
**Status:** M1 development stack is up. A four-service Docker Compose stack serves
a Slim 4 landing page with Tailwind CSS, configuration/logging, and cross-platform
task wrappers. There is no catalog application, database schema or migration runner
yet. See [the development stack setup](docker/README.md) for first-run instructions.
Do not deploy this as a production service.
## Planned MVP
@@ -33,8 +34,10 @@ management, external imports, AI and multi-user libraries are outside MVP.
## Architecture and decisions
Docker, PostgreSQL and PHP application logic; PHP-rendered templates with Tailwind
CSS and browser JavaScript. Node is planned for asset builds, with mesh processing
introduced only when those future features are scoped. No PHP framework is selected.
CSS and browser JavaScript. Node runs inside an assets container for deterministic
locked builds and watch; no host Node is required. Slim 4, PHP-DI and Monolog are
installed, locked and wired. HTTP, configuration, logging and task wrappers are
verified on the remote development host.
Accepted decisions: [managed storage (#1)](https://git.keithsolomon.net/keith/MeshVault/issues/1),
[dates (#2)](https://git.keithsolomon.net/keith/MeshVault/issues/2),
@@ -49,7 +52,7 @@ Local planning notes and ADR copies are deliberately not versioned.
| `src/` | PHP application and domain code |
| `public/` | Future HTTP document root and generated browser assets |
| `db/migrations/` | Ordered PostgreSQL schema migrations |
| `docker/` | Future container definitions and service configuration |
| `docker/` | Development container definitions, configuration and setup |
| `assets/` | Source assets, including the project icon |
| `tests/` | Automated checks and future application fixtures/tests |
@@ -57,18 +60,51 @@ Directory READMEs describe boundaries; they are not application implementations.
## Development checks
With PHP 8.3+ and Composer 2 installed:
The only host prerequisite is Docker Compose v2+ with Linux containers. All PHP
and Node tooling runs inside containers.
```sh
composer install --no-interaction
composer validate --strict
composer lint
composer test
# Start the stack (builds images if needed)
./dev.sh up
# Or on Windows: .\dev.ps1 up
# Run checks inside the app container
./dev.sh test
./dev.sh lint
# Build minified assets inside the assets container
./dev.sh assets
# Watch for template changes
./dev.sh watch
```
These commands validate foundation files and PSR-12 configuration, not application
behavior. See [CONTRIBUTING.md](CONTRIBUTING.md) for conventions and test limitations.
Container-based development, migrations and frontend build commands arrive in M1.
`composer test` and `composer lint` also work on a host with PHP 8.3+ and Composer 2.
`composer audit` checks locked PHP dependencies. `migrate` and `seed` are unavailable
until M2 (#12); they exit nonzero and leave #10 open.
Asset builds use a locked `package-lock.json` inside a container; host Node is not
required. The generated `public/build/app.css` is served statically by nginx.
### Configuration and logging library
`MeshVault\Config\AppConfig::fromEnvironment(array $environment)` accepts explicit
string values; supported keys, defaults and validation rules are in `.env.example`.
Native PHP does not read `.env`: export the variables through your shell/process
manager, then pass `getenv()` to the factory after requiring `vendor/autoload.php`.
Compose environment injection/startup validation will be wired in Task3. Validate as
the actual runtime user, not root. The library never creates or chmods library roots.
Readonly properties: `environment`, `libraryPath`, `dbHost`, `dbPort`, `dbName`,
`dbUser`, `dbPassword`, `logLevel`. Configuration JSON/debug/serialization is redacted;
serialized configuration cannot be restored. Read credentials only at their point of
use: do not cast configuration to arrays or log credentials/messages containing them.
This is not a general-purpose sanitizer for arbitrary caller-supplied secrets.
`MeshVault\Logging\LoggerFactory::create($config)` returns a PSR-3 logger writing
newline-delimited JSON to stdout at the configured level. `forJob($logger, $jobId)`
returns an independent scope; its `job_id` takes precedence over caller context,
while other context is retained. Re-scoping replaces the job ID; the base logger
and other jobs are unchanged. FPM forwarding remains a Task3 verification gate.
## License