Getting started
Everything runs in Docker; you do not need PHP or Composer on the host.
Run the platform
make up # build + start the stack (app on http://localhost:8080)
make logs # tail application logs
make ps # container status
make down # stop
Verify it is up:
- Health: http://localhost:8080/health
- API docs (Swagger UI): http://localhost:8080/api/docs
Bootstrap the database
The metadata tables and the Base package (default language, roles, seed entities/views/forms)
are created by the bootstrap command. Run it on a fresh database, and again after any schema
(ddl) or seed change — otherwise the API errors on the missing tables/columns:
make console ARG="syntec:bootstrap"
Rule of thumb: changed a
CREATE TABLE/ALTER TABLEinMetadata/Persistence/Bootstrap.php, or added a seed? Re-runsyntec:bootstrapagainst the live DB.
Other useful console commands (run via make console ARG="..."): syntec:schema:index
(introspect physical tables into metadata), syntec:auth:keys (generate the JWT keypair).
Run the tests
make test # full PHPUnit suite (in the container)
docker compose exec -T app php bin/phpunit --filter SomeTest # a single test/class
Tests use a real Postgres (DatabaseTestCase) and run Bootstrap to set up metadata. Keep the
suite green before committing.
Project layout
docker/ # Dockerfile (FrankenPHP + extensions)
compose.yml # app (FrankenPHP) + db (Postgres)
app/ # the Symfony application
src/ # the engine + Base package (see Concepts)
tests/ # PHPUnit suites mirroring src/
bin/console # Symfony console (syntec:* commands)
VERSION # current platform version
Working in the codebase
- Add a new route → also add it to
OpenApiGeneratorso/api/docsreflects the whole API. - Change metadata DDL or seed → re-run
syntec:bootstrap(above). - Follow TDD — write the failing test first; the suite is the contract.
See Concepts for the metadata model and the engine.