Nafinity¶
Project-isolated Kanban boards, and the largest thing built with NAF so far. It is here because it answers a question the rest of this documentation can only assert: what a real application looks like when the framework stays small and everything else is a plugin.
A Nafinity installation loads twenty plugins. The application itself is one of them.
The split¶
The repository you clone is a skeleton. The product is a dependency.
naf/nafinity the installation you own
└── naf/board everything the application does
└── naf/framework and eighteen other plugins
That is the point rather than a packaging detail: extending Nafinity must never mean
editing it. Everything the product does lives in naf/board; everything you decide lives
in the skeleton, which is small enough to read in a minute.
app/
composer.json what your installation requires
bootstrap.php nine lines: autoload, BASE_PATH, run
.env the application's own environment
src/
config.php everything the application runs on, in one file
routes.php routes you add; a path here wins over the board's
plugins.php the order plugins boot in
extensions.php your last word on what the application offers
Controllers/ your code, namespace Nafinity\
views/ a template here wins over the board's
public/index.php the entry point; assets are published in beside it
storage/ uploads, sessions, queue and scheduler state
docker/, Makefile how it runs locally
There is deliberately almost nothing there. A fresh installation is a complete application, and none of it is a file you could break by editing.
Running it¶
Nafinity ships with Docker Compose and a Makefile. One command builds the image, installs dependencies, migrates, writes the declared roles, publishes assets, seeds a demo project and starts everything:
make first-install
It is then at https://localhost, with a locally trusted certificate the same command
issued. make help lists the rest; the ones you will want early are make assets after
updating a package, make migrate, and make logs.
The stylesheets and scripts live inside naf/board and every plugin, so they are copied
into app/public/ rather than checked in. A package added later is registered and absent
at the same moment, which a browser reports as a 404 on a module tag — which is to say
silently. make health compares the two and turns that silence into a sentence.
The commands it brings¶
make wraps the ones a development installation needs daily; these are what it wraps, and
what a deployment runs directly.
| Command | What it does |
|---|---|
nafinity:seed |
Demo data, and only into a database that has none |
nafinity:assets:publish |
Copy every package's stylesheets and scripts into app/public/ |
nafinity:assets:check |
Report registered assets that were never published — a 404 on a module tag is otherwise silent |
nafinity:assets:remove |
Take published files back out, from the record written when they went in; works after the package is gone, which is the point |
nafinity:user |
Create an account, reading its password from standard input |
nafinity:admin |
Grant the admin role to an existing account, while nobody holds it yet |
nafinity:grant-default |
Give accounts holding no role at all the one an ordinary account has |
nafinity:migrations:rename |
Rewrite the namespace recorded for applied migrations, after renaming your own |
The first four are what make assets, make seed and make health call. The rest are for
the moments an installation is being set up or repaired, which is why they are commands rather
than screens.
Making it yours¶
Your own code goes in app/src/ under the Nafinity\ namespace. The namespace is
yours: nothing in naf/board refers to it, so rename it in composer.json if you would
rather call it something else.
Overriding a template. Copy the one you want from vendor/naf/board/src/views/ into
app/src/views/, keeping the path. Host views win over the package's.
Changing what the application offers. app/src/extensions.php runs after the board
and every plugin has registered, so anything reachable there can be replaced or removed —
including a definition a plugin just added:
use function Naf\Board\extensions;
extensions()->boardFilters()->remove('example.only-mine');
Adding a plugin. composer require it. A package of type naf-plugin is found
through Composer's installed-packages metadata, so there is nothing to register; list it
in app/src/plugins.php only when its position in the boot order matters.
For the mechanisms a plugin has once it is installed, see how Nafinity is extended.
What it is made of¶
Nafinity uses most of the NAF ecosystem rather than a corner of it, which is the other reason it is worth reading as an example.
| It needs | For |
|---|---|
naf/view |
Templates, with host paths winning over package paths |
naf/database, naf/orm |
Schema migrations, repositories |
naf/auth, naf/session |
Signing in against its own user model |
naf/form |
Validation and CSRF |
naf/queue, naf/schedule |
Notification mail, reminders |
naf/storage |
Ticket attachments |
naf/i18n |
German source strings, English translation |
naf/cli |
nafinity:seed, nafinity:assets:publish and friends |
naf/rate-limit |
Slowing down sign-in attempts |
naf/mcp |
Exposing tools to a local model |
naf/rbac |
Roles and permissions an installation can edit |
naf/websocket |
Live updates, and who else is on a board |
Where the rest is written¶
The extension reference — every registry, every contract, what a plugin may declare and
what happens when it is removed — ships with the board itself, in docs/Extensibility.md
of naf/board. It is exhaustive and versioned with the code it describes, which a page
here could not be.
This chapter is the map. That file is the territory.