Add development guidelines, testing rules, and secure routes documentation

- Add `.junie/guidelines.md` with comprehensive development instructions.
- Include `.aiassistant/rules/Creating and maintaining tests.md` and `.aiassistant/rules/Creating and securing routes.md`.
- Introduce `CACHE_SELFSERVE_LANE_KEY_ALLOWED_SERVICES` for lane service validation.
- Update `selfserve_lane_relay_controller_t` to enforce service-specific permissions for machine relay.
This commit is contained in:
Jeppe Bundgaard
2026-02-18 14:13:05 +01:00
parent 008e2af09a
commit 51014bf774
8 changed files with 800 additions and 0 deletions
+148
View File
@@ -0,0 +1,148 @@
### Copenhagen Truck Wash API — Development Guidelines (Projectspecific)
#### Scope
This document captures projectspecific knowledge for building, configuring, testing, and extending the API. It assumes an advanced developer familiar with Docker, PHP 8.2, and HTTP APIs.
---
### Build and Configuration
- Stack overview (local):
- Reverse proxy/router: Traefik 2.x (`docker-compose.yml` service `traefik`).
- Web server: Caddy (`caddy`) serving the PHP app from `services/nginx/app` and proxied by Traefik.
- PHP runtime: Multiple PHPFPM containers (`php1`..`php5`), sharing the bindmounted app directory.
- Redis: `redis` for caching/queues/locks.
- App location: `services/nginx/app` is the effective application root (many scripts/tests derive `WD` to point here).
- Composer and dependencies:
- `services/php/Dockerfile` installs Composer and PHP extensions.
- `services/php/docker-entrypoint.sh` performs a guarded Composer install on `php1` at container start when `AUTO_COMPOSER_INSTALL=true` and `composer.json` is present.
- App dependencies live under `services/nginx/app/composer.json` (note: very light, primarily runtime libs; dev tool `rector/rector`).
- Configuration source of truth during containerized runs is environment variables consumed by `services/nginx/app/config.php`.
- `config.php` requires `USE_ENV=true`; otherwise it throws an exception. Many CLI scripts/tests bypass `config.php` entirely to remain envagnostic.
- Local run targets and routing:
- Traefik exposes:
- `http://localhost` → routes to Caddy → app (HTTP only for dev).
- `https://localhost` → also mapped, using Traefiks default/selfsigned dev cert.
- `http(s)://localhost/api/*` → Traefik stripprefix middleware forwards to Caddy; the app sees paths without the `/api` prefix.
- For productionlike HTTPS with real certs, see `README.md` for `LETSENCRYPT_PATH` mounting strategy (only needed if you want the exact `api.truckwash.dk` TLS behavior locally).
- Minimal bringup for local development:
- Prerequisites: Docker Desktop 4.x+.
- First run will build PHP images and start dependent services. Composer install runs automatically on `php1`.
- Recommended minimal set:
- `docker compose up -d traefik redis php1 caddy`
- Full set (scale out PHP or add observability as needed):
- `docker compose up -d` (starts `traefik`, `redis`, `caddy`, `php1`..`php5`, and other declared services).
- Logs:
- `docker compose logs -f caddy`
- `docker compose logs -f php1`
- `docker compose logs -f traefik`
- Security note: `docker-compose.yml` currently embeds sensitive env values (DB, API tokens). Treat the file as secret in private repos; never republish as is. Prefer `.env` overrides and secrets providers for wider teams.
---
### Testing
The repository does not use PHPUnit for the app. Instead, tests are lightweight CLI scripts under `services/nginx/app/tests`. Conventions:
- Test style
- Selfcontained procedural PHP scripts intended to be executed with `php`. No framework required.
- Many tests define the `WD` constant to the app root and then `require_once` specific class/trait/interface files they exercise.
- Integrationstyle scripts that need configuration will rely on `services/nginx/app/config.php` and so must run within a properly provisioned environment (Docker containers with `USE_ENV=true`).
- Fast unitstyle scripts should avoid `config.php` and any I/O; they manually include only whats needed and/or use test doubles.
- Running tests from host (fastest path)
- Prereq: PHP CLI available on host. Verified with:
- `php -v` → observed on our env: `PHP 8.2.30 (cli)`
- Example: an existing, fully selfcontained test validating subuser permission wiring:
- Command:
- `php services/nginx/app/tests/subusers/SelfservePermissionInitTest.php`
- Verified output (captured):
-
```
✔ SELFSERVE_ADD is granted as expected
✔ SELFSERVE_LIST is not granted as expected
✔ SELFSERVE_EDIT is not granted as expected
✔ SELFSERVEDELETE is not granted as expected
SelfservePermissionInitTest completed.
```
- Running tests inside Docker (when host PHP is unavailable or when env is required)
- Ensure containers are up: `docker compose up -d traefik redis php1 caddy`
- Execute a test within `php1`:
- `docker compose exec -T php1 php /var/www/html/tests/subusers/SelfservePermissionInitTest.php`
- For integration tests that depend on `config.php` (e.g., Redis/DB), environment variables are preconfigured in `docker-compose.yml` for the PHP services. Running inside `php1` will satisfy `USE_ENV=true`.
- Adding a new test
- Place the file under `services/nginx/app/tests/<domain>/YourTest.php`.
- At top of the file, define `WD` if not already defined:
```php
if (!defined('WD')) { define('WD', dirname(__DIR__, 2)); }
```
- Prefer selfcontained tests that avoid I/O. If you need to touch internal classes without Composer autoloading, include files directly, mirroring existing tests.
- If the test must hit Redis/DB or rely on globals from `config.php`, run it inside a PHP container (`php1`) with `USE_ENV=true`.
- Demonstration: creating and running a minimal test
- We created a temporary, envagnostic test at `services/nginx/app/tests/examples/HelloWorldTest.php` with these semantics:
- Define `WD`, perform trivial assertions, and print success markers.
- Command executed and verified output:
- Command:
- `php services/nginx/app/tests/examples/HelloWorldTest.php`
- Output (captured):
-
```
✔ Basic arithmetic works (2 + 2 = 4)
✔ WD points to the application root: C:\\Users\\2jepp\\PhpstormProjects\\api\\services\\nginx\\app
HelloWorldTest completed.
```
- The example file was removed afterwards to keep the repository unchanged. You can replicate by creating a similar file and removing it after execution.
---
### Additional Development Information
- Routing and HTTP surface
- Routes live under `services/nginx/app/routes`. Example route `exampleRoute.php` exposes `GET /example` returning `{"message":"Hello World!"}`. Local access paths (with Traefik):
- `http://localhost/example` (direct)
- `http://localhost/api/example` (Traefik stripprefix `/api` → still routes to `/example` in the app).
- The OpenAPI contract is at the repo root `openapi.yaml` (large, authoritative). Keep it synchronized with implemented routes and payloads.
- Module layout and traits
- Domain modules live in `services/nginx/app/modules/*` and are heavily traitbased. Tests often pull in precise files from here to avoid full app bootstrap.
- Example: subusers module (`modules/subusers/...`) provides permission node containers and helpers. The test `tests/subusers/SelfservePermissionInitTest.php` demonstrates overriding DBbacked methods to inject permissions for fast, deterministic checks.
- Config and globals
- `services/nginx/app/config.php` populates globals like `$CONFIG_DB`, `$REDIS_CONFIG`, etc., but only when `USE_ENV=true`. If you see tests throwing “Environment variables are not set”, run them inside Docker or set required envs for host PHP.
- Code style
- `.editorconfig` at repo root configures formatting. Key PHP rules:
- Encoding: UTF8 with CRLF line endings.
- Indent: 4 spaces; continuation indent 4.
- Class brace style: next_line; function/method blank lines: 1.
- Import sorting: alphabetic; various alignment toggles are disabled.
- Match existing patterns (procedural scripts for tests; namespacing in app code; traits for crosscutting concerns). Avoid adding new frameworks for tests unless explicitly requested.
- Composer / Autoload
- There is no Composer autoload configured for the app code in `composer.json`; tests include files directly. If you introduce autoloading, coordinate with Docker entrypoint behaviors and ensure zerodowntime for existing scripts.
- Performance & reliability hints for tests
- Prefer small, deterministic CLI scripts; inject dependencies and override I/O methods (as shown in `SelfservePermissionInitTest.php`).
- Avoid hitting external services (Stripe, economic, MinIO) from tests; instead, stub/override or provide fakes.
---
### Quick Reference
- Bring up minimal dev stack:
- `docker compose up -d traefik redis php1 caddy`
- Run a fast, selfcontained test (host PHP):
- `php services/nginx/app/tests/subusers/SelfservePermissionInitTest.php`
- Run a test inside Docker (envbacked):
- `docker compose exec -T php1 php /var/www/html/tests/subusers/SelfservePermissionInitTest.php`