Skip to content

v0.1.0 — Project-isolated Kanban boards, as a plugin

Choose a tag to compare

@FloKnapp FloKnapp released this 21 Sep 19:16
· 139 commits to main since this release
5cee1c2

Project-isolated Kanban boards, as a NAF plugin. The application behind a Nafinity installation.

The first release. It is a plugin rather than an application on purpose: the skeleton you install is yours to edit, and everything the product does lives here, where an upgrade can replace it.

Boards that cannot see each other

Every table carries project_id, and every foreign key is composite. A ticket references its column and its project, so a row cannot point across a boundary even by mistake — the schema refuses it rather than a query remembering to filter. Somebody who is not a member gets a 404 that does not say whether the project exists.

Membership decides whether you reach a board. What you may do there comes from naf/rbac, scoped to that board, which is how an administrator's rights apply inside a project they were never added to.

What a plugin can do to it

Sixteen registries for what exists, three events for what is happening, and no third mechanism. Not a hook manager beside an event system beside a filter chain.

A plugin adds ticket fields, field types, priorities, board filters with their own SQL, estimation scales, activity types, export formats, permissions that appear in the role editor, settings, navigation, slot contributions, and replacements for any view or core service. Contributed ticket fields are stored as ticket metadata, typed, permission-guarded, and inert when the plugin is gone: values of an absent package stay where they are and the application can name them.

Events are nafinity.changed for anything written, rbac.granted, and export.line. The first is dispatched inside the transaction that did the work, so a listener that throws refuses the write — which is how a rule no permission can express gets to stop something.

Two example extensions ship with the package and are booted by the test suite, once with them installed and once without.

Exporting

A board can be written as CSV or JSON, and a plugin can add a third format with one registration. The rows are built once, in one service, so every format sees the same board; export.line fires per record, and a listener may change what is reported without the ticket moving — ExportLine::$ticket is readonly and PHP enforces it.

Columns are the registered ticket fields, so a plugin's own field is in every export without the export having heard of it, with that field's read permission still deciding.

A complete audit trail

Every change to a project or the installation is recorded with its actor, its scope and what moved — settings, roles, grants, accounts, and each of the twenty-four things that can happen to a ticket. Reading it needs its own permission; personal account events need a second one. Deleting a user nulls the author rather than the entry, and the log says "deleted user".

Live updates

With naf/websocket installed, a board rearranges itself as other people work: the socket carries that something changed and never what, and the page fetches the new state through the ordinary path. A single card arrives on its own rather than the board reloading. Presence shows who else is in the project and what they have open, per person rather than per connection, and switching it off takes the channel out of the token rather than hiding a list.

Also in it

Comments with mentions, attachments on named storage disks, time tracking, ticket links and transfers between boards, swimlanes, WIP limits, estimation scales, saved filters, notification mail through the queue, LDAP and OAuth sign-in, German and English throughout, and optional tools for a local model.

Verification

98 unit, 195 database on MariaDB and PostgreSQL, 3 worker, 155 HTTP against a real server over HTTPS, 49 JavaScript, 128 across four extension-host configurations. PER Coding Style 3.0.

Requires

PHP 8.3 with pdo, mbstring, fileinfo and dom. Twenty NAF packages, including naf/rbac ^0.1.0; naf/websocket is optional and only needed for live updates. See naf/nafinity for the installation skeleton and docs/Extensibility.md for the extension reference.