Getting Started with Pramnos Framework¶
Welcome to the Pramnos Framework! This guide will help you set up a new project from scratch using our command-line tools.
Installation¶
The recommended way to start a new project is to use the Pramnos Application. This provides a one-line setup experience that automatically handles the directory structure and framework installation.
- From your projects root directory, run:
Alternatively, if you prefer to manage the process manually or add the framework to an existing project:
- Create your project directory:
- Install the framework:
- Run the initialization command:
The init command will guide you through the setup with smart defaults:
- Application Name: Defaults to the folder name (my-app).
- Namespace: Automatically converted to CamelCase (MyApp).
- Database: Suggested name (my_app_db) and user (my_app_user).
- Docker: Optional but highly recommended containerized setup.
Using Docker¶
If you enabled Docker during initialization, first start your environment:
Note: Ensure Docker and Docker Compose are installed on your host machine.
Helper Scripts¶
./dockerbash: Enter the application container's shell../dockertest: Run your PHPUnit tests inside the Docker environment.
The daemons container¶
If the features you enabled have background work — queue, messaging, broadcasting, or
the periodic jobs auth and authserver schedule — init also writes a daemons service and
src/ConsoleCommands/Daemons.php, the supervisor it runs.
It is there so that development runs the same background work production does. Without it a fresh project's queue fills and nothing empties it, and the scheduled cleanups never run — and neither of those announces itself. What you see is a screen with no rows on it, a job that stays queued, a token that never expires, each of which reads as a bug in the code that would have used them.
Add a worker of your own in buildDesiredProcesses(); the framework's schedule worker is
supervised without being declared. /admin/Services shows what it is running, and
Workers & Daemons has
the systemd unit for a server.
Project Structure¶
A typical Pramnos project following initialization looks like this:
app/: Configuration and Migrations.config/settings.php: Main environment configuration — reads.env, holds no credentials, identical in every checkout.config/testsettings.php: The same, pointed atAPP_DB_TEST_NAME.
.env: this machine's values — credentials, database name,APP_DEBUG. Not committed..env.example: the committed list of every key, secrets blank. Copy it to.env.src/: Your application logic (Controllers, Models, Views).www/: Public entry point (containsindex.phpand assets).var/: Logs, cache and migration state. Entirely machine-local — the whole directory is in.gitignore, and every writer creates what it needs, so a fresh clone with novar/at all is correct.tests/: Unit and Integration tests.
Configuration and secrets¶
Nothing init writes into version control contains a credential. The values live in
.env, which is in .gitignore; app/config/settings.php reads them and is the same
file in every checkout:
'database' => [
'type' => envvar('APP_DB_TYPE', 'postgresql'),
'hostname' => envvar('APP_DB_HOST', 'db'),
'database' => envvar('APP_DB_NAME', 'myapp_db'),
'user' => envvar('APP_DB_USER', 'myapp'),
'password' => (string) envvar('APP_DB_PASSWORD', ''),
...
],
'development' => envvar('APP_DEBUG', false),
docker-compose.yml interpolates from the same file — POSTGRES_PASSWORD:
${APP_DB_PASSWORD} — so a credential has one home and one place it can leak from.
Four things are worth knowing:
APP_DB_*, notDB_*. A real environment variable deliberately beats.env, so that a host which injectsAPP_DB_PASSWORDneeds no file. The bare names are the convention and also the ones a hosting image, a CI runner or a sibling container is most likely to have set already — for a different database. That is not a hypothesis: this framework's own dev container exportsDB_HOST,DB_USERandDB_NAME, and the first run of the scaffolding tests after this change readpramnos_testout of a project configured for something else.- The defaults in the file are the non-secret ones. Host, database, user and prefix
have one;
APP_DB_PASSWORDdoes not. A clone with no.envfails to authenticate, which points at the missing file, rather than failing to find a database. APP_DEBUGistruein the.envinit writes andfalsein.env.example.initis setting up a development machine; the next place that file is copied might not be one.'development' => trueused to be frozen into a committed file..env.examplelists every key — the test suite asserts the two files have the same key set — so a diff of the two is exactly what a new checkout must be told.
After a fresh git clone, cp .env.example .env and fill in the blanks — or let
project:setup do it and bring the environment up with you.
What init puts in .gitignore, and why¶
| Entry | Why |
|---|---|
/vendor/ |
Composer restores it from composer.lock |
/var/ |
Everything under it is state this machine wrote: caches, logs, var/migrations/*.verified (a per-database verification timestamp) and var/migrations-schemaversion.lock (a worker lock carrying a pid, a hostname and a heartbeat) |
/.env |
The credentials, the database name, APP_DEBUG and this host's user ids. .env.example is the committed copy of its shape |
node_modules/ |
npm restores it from package-lock.json. Ignored in every project, not only ones with a build stack: npm install runs at the project root for the OpenAPI/RapiDoc generator too, and ./dockernpm is there for anyone to use |
/app/keys/private.key, /app/keys/encryption.key |
Only when the authserver feature is on. public.key is committed — it is public |
www/api/openapi*.json, www/api/docs/ |
Only when API docs are on; regenerated by ./dockernpm run docs:build |
<web-root>/<build-dir>/ |
Only for a SPA with a build stack; produced by npm run build |
.mcp.json and CLAUDE.md are committed on purpose. They are project
configuration, and the point of them is that whoever clones the repository next gets
the MCP server and the assistant guidelines without being told they exist. Neither
holds a credential.
www/assets/vendor/ is committed — the vendored front-end libraries are part of
what gets deployed, and a clone with no network still renders. ./pramnos
project:install re-downloads them when you need it.
To run your tests, use the following command:
The ./dockertest command runs PHPUnit inside the Docker container (PHP 8.4), ensuring all dependencies and environmental requirements are met. It automatically handles container startup and composer installation if needed.
Creating Entities¶
Once your project is initialized, you can use the create command to scaffold new components: