Looking to hire Laravel developers? Try LaraJobs

laravel-kradan maintained by phattarachai

Description
A review board inside your Laravel app: Claude pushes pages that ask for a decision; your signed-in users pick options, comment and pin; Claude pulls the answers back.
Last update
2026/10/28 10:18 (dev-main)
License
Links
Downloads
1

Comments
comments powered by Disqus

Laravel Kradan

Latest Version on Packagist Tests Code Style PHP Version Laravel Version Total Downloads

A review board inside your Laravel app. Claude pushes designed pages that ask for a decision; your signed-in users pick options, comment, reply and drop pins; Claude pulls the answers back as review.md.

Kradan (กระดาน, "board") is for the moment a design or a business rule needs answers from the people who use the app, not only from the developer. Nothing is committed or deployed to show them a page: one command puts it on the board, and one command brings the answers back.

Requirements

  • PHP 8.4, Laravel 12 or 13
  • The zip and dom extensions
  • An authenticated user model. Kradan has no accounts of its own: it reviews with your app's users.

Install

composer require phattarachai/laravel-kradan
php artisan migrate

Enable it on the one environment your team reviews on (a staging or QA box), and leave it off everywhere else:

KRADAN_ENABLED=true

With KRADAN_ENABLED=false (the default) no route is registered at all, so every Kradan URL is a 404.

The board's JavaScript and CSS ship prebuilt and are served by the package, so there is no vendor:publish and no frontend build in your app. php artisan kradan:doctor checks the install.

If your app uses Laravel Boost, composer require runs boost:update, which rewrites the host's Boost skills. In a checkout without node_modules it can drop skills of unrelated packages; check git status afterwards and restore them.

Access

Register who may open Kradan in a service provider. $ability is view or manage; manage may mark a decision board decided.

use Phattarachai\Kradan\Kradan;

Kradan::auth(fn ($user, string $ability): bool => $user->isAdmin());

// Optional: how a person is shown. The default is the `name` attribute and initials.
Kradan::userUsing(fn ($user): array => [
    'id' => $user->id,
    'name' => $user->name,
    'avatar' => $user->avatar_url,
]);

Without a callback only the local environment lets signed-in users in. A guest is sent to your login route; if your login route has another name, set it, or guests get a 403. For a Filament admin panel:

KRADAN_LOGIN_ROUTE=filament.admin.auth.login

kradan:doctor reports a route name that does not exist.

What it does

  • Decision boards. Each board, at /kradan/<slug>, holds options to pick from. Once marked decided it moves to history: picks lock and comments stay open. /kradan lists every board with search over titles, task references and step titles. A page that only explains something belongs in your docs, not on a board.
  • Open answering. Anyone allowed in may pick, comment or pin on any step, and everyone sees who picked what. The board shows how far each person got.
  • Rounds. A push with the same data-dp title replaces the latest round; a new title opens the next round. Earlier rounds stay readable and read-only.
  • Notes, files and drawings. Users add sticky notes, text, images, files, arrows, boxes and freehand lines beside or over a screen, and reply to them. Anyone may move an item; only its author edits or deletes it. Uploads are limited by kradan.uploads (size and file extensions). Images show through the sandboxed content prefix; every other file only downloads, so nothing uploaded runs on your app's origin.
  • History and presence. Who viewed (at most one entry per person per 30 minutes), picked, commented and pinned. Avatars show who is on the board now, over a Reverb presence channel when your app broadcasts with Reverb, or from a 30-second heartbeat otherwise. The browser connects to the host, port and scheme of the reverb.apps entry with your broadcasting key, so an app that publishes to Reverb on loopback still sends browsers to its public address.

Safety model

Pages Claude made run their own JavaScript. Served from your app's origin, that script would act with the viewer's session. Kradan prevents that:

  • Round files are served under a path-signed, expiring prefix: /kradan/f/{round}/{expires}/{signature}/…. The signature covers the round and the expiry, so relative links inside a page keep working. No session or cookie is involved.
  • Every content response carries Content-Security-Policy: sandbox allow-scripts and X-Content-Type-Options: nosniff, so the page runs in an opaque origin even when opened directly.
  • The board talks to each sandboxed frame only over postMessage, through a small agent script the package injects. It never reads the frame's DOM.
  • Paths are normalised and anything climbing out of the round folder is refused, both in uploaded zips and in content URLs.

For a stricter split, serve content from a separate host that points at the same app:

KRADAN_CONTENT_URL=https://design.example.com

Pushing and pulling (for Claude)

The kradan:* commands run in a developer's checkout and call the server's token API.

php artisan kradan:token --write     # token into the local .env, prints only its sha256

Add that hash to the server (a comma list, so tokens rotate without downtime) and point the checkout at it:

# server
KRADAN_TOKEN_HASHES=3f2a…,9b1c…

# developer checkout
KRADAN_REMOTE_URL=https://staging.example.com
KRADAN_REMOTE_TOKEN=…written by kradan:token --write
Command What it does
kradan:push <dir> [--slug=] [--task=] [--dry-run] Zips a design folder (index.html) and pushes it as a round; prints the board URL
kradan:pull <slug|board url> [--to=] Writes rounds/NN/review.json and review.md per round, the latest as review.md, and every uploaded image and file into attachments/
kradan:list Every board, its status and latest round
kradan:decide <slug> Marks a board decided
kradan:doctor Checks the install

The package ships a Laravel Boost skill, so php artisan boost:install teaches Claude this workflow in your project.

A pushed folder needs an index.html. Pages use the markup of the design workbench: data-dp on <body> for the round title, data-dp-step with data-title for each step, data-dp-option with data-key and data-label for options, data-dp-group for sections and data-dp-frames with data-src for live screens.

Configuration

php artisan vendor:publish --tag=kradan-config
Key Env Default
enabled KRADAN_ENABLED false Off means every URL 404s
path KRADAN_PATH kradan
connection KRADAN_DB_CONNECTION default Holds the kradan_* tables
disk KRADAN_DISK local Round files go under kradan/<slug>/<round>/
content_url KRADAN_CONTENT_URL null A separate content host
signed_ttl KRADAN_SIGNED_TTL 240 Minutes a content URL stays valid
brand KRADAN_BRAND, KRADAN_LOGO, KRADAN_ACCENT app name
theme KRADAN_THEME kradan kradan, workbench or a token map, see below
redirect_guests_to KRADAN_LOGIN_ROUTE login Route name or URL a guest is sent to; null 403s
presence KRADAN_PRESENCE auto auto, reverb, polling or off
uploads.max_kb KRADAN_UPLOAD_MAX_KB 20480 Largest image or file a user may add
uploads.types images, pdf, office, csv, txt, zip Allowed file extensions
tokens KRADAN_TOKEN_HASHES none sha256 hashes, comma separated
locale KRADAN_LOCALE th th or en

Theme

The board is green by default. To match your app, pick another theme or override its tokens in config/kradan.php. Tokens are the board's CSS custom properties without the leading --:

'theme' => [
    'name' => 'kradan',          // optional: the theme the tokens sit on
    'k-accent' => '#ba1a1a',     // the accent, Kradan's green
    'chrome' => '#1f2937',       // the top bar and toolbars
],

Values must be a colour (#hex, rgb(), hsl(), oklch(), a keyword) or a length (260px, 1.5rem). Anything else is dropped before it reaches the page, and kradan:doctor names it. brand.accent still colours the workspace badge.

Translations

Thai is the default. Publish the language files to change the wording:

php artisan vendor:publish --tag=kradan-lang

Testing

composer test

Licence

MIT. See LICENSE.md.

ผู้พัฒนา

พัฒนาและดูแลโดย บริษัท ภัทรชัย อาร์ทิซาน จำกัด (Phattarachai Artisan) บริษัทที่ปรึกษาและพัฒนาเว็บ ที่เรียนรู้และแบ่งปันกับชุมชน Laravel แพ็กเกจนี้แบ่งปันให้ชุมชนนำไปใช้และต่อยอดได้อย่างอิสระ

ดูแพ็กเกจอื่นของเราได้ที่ phattarachai.dev/open-source และติดต่อเราได้ที่ phattarachai.dev