Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
kinetix-kanban
happones/kinetix
claude-code
kanban
drag-and-drop
inertia
vue
authorization
multi-tenant
enum

Drag-and-drop board over an Eloquent model: records grouped into columns by a status attribute; dragging a card persists the new status. Activates when building a Kanban/status board.

Install
php artisan boost:add-skill happones/kinetix

Save this content to: .claude/skills/kinetix-kanban/SKILL.md

# Kinetix Kanban Development

## When to Apply

Activate this skill when:
- Building a status board / Kanban over a model (tasks, leads, tickets…).
- Rendering `<KinetixKanban>` or letting users drag cards between statuses.

## Documentation

For full details, reference `docs/kanban.md` (published at https://happones.github.io/kinetix/kanban).

## Backend (server-driven, like Tables)

```php
use Happones\Kinetix\Kanban\Kanban;

$board = Kanban::make(Task::query())
    ->statusColumn('status')
    ->statuses([
        'todo'  => 'To Do',
        'doing' => ['label' => 'In Progress', 'color' => '#3b82f6'],
        'done'  => ['label' => 'Done', 'color' => '#22c55e'],
    ])
    ->cardTitle('title')
    ->cardDescription(fn (Task $t) => $t->assignee?->name)
    ->query(fn ($q) => $q->where('archived', false));

return Inertia::render('Tasks/Board', ['board' => $board->toData()]);
```

No migration or config flag. `toData()` bakes a signed descriptor; the
`POST {prefix}/tables/kanban-move` endpoint (always registered) decrypts it and
only writes the declared status column to one of the declared statuses.

### Enum status columns

A `statusColumn` cast to a PHP enum works natively: grouping stringifies
`BackedEnum` → backing value / `UnitEnum` → case name, and the move re-casts the
plain string. Use the backing values as the `statuses()` keys.

### Record-level authorization (multi-tenant — use at least one)

- **Policy (automatic)**: when the model has a registered policy, every move is
  authorized against it — `update` by default, or `->authorizeMove('moveCard')`
  for a specific ability. Denied → 403 + card snaps back.
- **`->moveScope(['team_id' => $teamId])`**: column=>value constraints evaluated
  in the request, sealed in the encrypted descriptor and enforced on the move
  lookup (outside → 404). Without one of these, any authenticated user who can
  guess a record id can move records of other tenants.

## Frontend

```vue
<KinetixKanban
    :kanban="board"
    @card-click="(card, columnKey) => …"
/>
```

Native HTML5 drag-and-drop (no extra dependency), with a long-press touch
fallback on mobile (floating clone follows the finger; edge auto-scroll).
While dragging, the source card dims, the hovered column highlights and shows
a dashed ghost placeholder previewing where the card will land; cards
FLIP-animate into place (respects `prefers-reduced-motion`). Moves are
optimistic (revert + toast on failure) and trigger a `router.reload()` on
success. Keyboard: left/right arrows move a focused card between columns;
Enter fires `card-click`. i18n `kanban_*` (en/es/fr/pt/zh/ja/ru).

`->reorderable('sort_order')` keeps a manual order within each column:
- cards show in that order, then by key;
- a drop lands at the slot under the pointer or finger, with the ghost at that slot;
- dragging within a column reorders it, and up/down arrows move a card one place;
- the move posts the destination column's `order`, and status + positions save
  in one transaction (write-checked, all-or-nothing);
- positions are traded via the shared `Support\ManualOrder` (same as table
  reorder), so cards a narrower board hides keep theirs; a card from another
  column takes a free position between its neighbours (else after the last);
  only cards whose position changes are written and write-checked; an
  unnumbered column is numbered once within `moveScope()`.

## Adding & editing cards (CRUD wiring)

The board only moves cards; CRUD is regular page wiring. Preferred: an
in-page modal — a `KinetixPageHeader` action with `->dispatch('task-create')`,
the page listens for `kinetix:task-create` and opens a `KinetixModal` hosting
`<KinetixForm :form="taskForm" flat @submit="submit" />` (**always pass `flat`
in modals** — the panel is the surface; Sections must not nest a card inside
it); `@card-click` opens the same modal for edits. Controllers persist,
flash `KinetixFlash::success(__('kinetix.record_created'))`
(`record_updated`/`record_deleted` for the other verbs) and `return back()`.
Alternative: dedicated pages via `router.visit()` on `card-click`, with the
page controllers flashing the same way before they redirect. Full example: docs/kanban.md
"Adding & editing cards".

Kinetix Kanban Development

When to Apply

Activate this skill when:

  • Building a status board / Kanban over a model (tasks, leads, tickets…).
  • Rendering <KinetixKanban> or letting users drag cards between statuses.

Documentation

For full details, reference docs/kanban.md (published at https://happones.github.io/kinetix/kanban).

Backend (server-driven, like Tables)

use Happones\Kinetix\Kanban\Kanban;

$board = Kanban::make(Task::query())
    ->statusColumn('status')
    ->statuses([
        'todo'  => 'To Do',
        'doing' => ['label' => 'In Progress', 'color' => '#3b82f6'],
        'done'  => ['label' => 'Done', 'color' => '#22c55e'],
    ])
    ->cardTitle('title')
    ->cardDescription(fn (Task $t) => $t->assignee?->name)
    ->query(fn ($q) => $q->where('archived', false));

return Inertia::render('Tasks/Board', ['board' => $board->toData()]);

No migration or config flag. toData() bakes a signed descriptor; the POST {prefix}/tables/kanban-move endpoint (always registered) decrypts it and only writes the declared status column to one of the declared statuses.

Enum status columns

A statusColumn cast to a PHP enum works natively: grouping stringifies BackedEnum → backing value / UnitEnum → case name, and the move re-casts the plain string. Use the backing values as the statuses() keys.

Record-level authorization (multi-tenant — use at least one)

  • Policy (automatic): when the model has a registered policy, every move is authorized against it — update by default, or ->authorizeMove('moveCard') for a specific ability. Denied → 403 + card snaps back.
  • ->moveScope(['team_id' => $teamId]): column=>value constraints evaluated in the request, sealed in the encrypted descriptor and enforced on the move lookup (outside → 404). Without one of these, any authenticated user who can guess a record id can move records of other tenants.

Frontend

<KinetixKanban
    :kanban="board"
    @card-click="(card, columnKey) => …"
/>

Native HTML5 drag-and-drop (no extra dependency), with a long-press touch fallback on mobile (floating clone follows the finger; edge auto-scroll). While dragging, the source card dims, the hovered column highlights and shows a dashed ghost placeholder previewing where the card will land; cards FLIP-animate into place (respects prefers-reduced-motion). Moves are optimistic (revert + toast on failure) and trigger a router.reload() on success. Keyboard: left/right arrows move a focused card between columns; Enter fires card-click. i18n kanban_* (en/es/fr/pt/zh/ja/ru).

->reorderable('sort_order') keeps a manual order within each column:

  • cards show in that order, then by key;
  • a drop lands at the slot under the pointer or finger, with the ghost at that slot;
  • dragging within a column reorders it, and up/down arrows move a card one place;
  • the move posts the destination column's order, and status + positions save in one transaction (write-checked, all-or-nothing);
  • positions are traded via the shared Support\ManualOrder (same as table reorder), so cards a narrower board hides keep theirs; a card from another column takes a free position between its neighbours (else after the last); only cards whose position changes are written and write-checked; an unnumbered column is numbered once within moveScope().

Adding & editing cards (CRUD wiring)

The board only moves cards; CRUD is regular page wiring. Preferred: an in-page modal — a KinetixPageHeader action with ->dispatch('task-create'), the page listens for kinetix:task-create and opens a KinetixModal hosting <KinetixForm :form="taskForm" flat @submit="submit" /> (always pass flat in modals — the panel is the surface; Sections must not nest a card inside it); @card-click opens the same modal for edits. Controllers persist, flash KinetixFlash::success(__('kinetix.record_created')) (record_updated/record_deleted for the other verbs) and return back(). Alternative: dedicated pages via router.visit() on card-click, with the page controllers flashing the same way before they redirect. Full example: docs/kanban.md "Adding & editing cards".

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect