vadykoo/laravel-todo-board
A Laravel package that adds a simple todo board to your application, letting you create, organize, and track tasks through an easy-to-integrate board interface. Lightweight and configurable, it covers common task-management needs without a full project suite. Best for small apps and prototypes.
vadykoo/laravel-todo-board v1.0.0 is the first public release, so there is no migration or upgrade path to worry about — every existing consumer is greenfield. Treat the 1.0.0 tag as "API is now public and semver-governed," not as "API is frozen"; expect minor additions in 1.x and read the changelog before every composer update.
Minimal setup, in order:
composer require vadykoo/laravel-todo-boardextra.laravel.providers in the package composer.json). If it is not, register it in bootstrap/providers.php (Laravel 11+) or config/app.php.php artisan vendor:publish --provider="Vadykoo\TodoBoard\TodoBoardServiceProvider" (or --tag=todo-board-config, --tag=todo-board-migrations). Publishing the config first lets you set table names and model bindings before the migration runs.php artisan migrateFirst use case: wire a board to an existing User and create one card end-to-end before touching anything else.
use Vadykoo\TodoBoard\Facades\TodoBoard;
$board = TodoBoard::boardFor($user); // or create()/firstOrCreate()
$board->addTask('Ship the assessment'); // status defaults to the first column
If that round-trips and shows up in the published views/routes, your config is correct and everything else is a variation on it.
Where to look first: the package README, then config/todo-board.php, then the migration stubs, then the source under src/. Because this is 1.0.0, the README is authoritative — there is no Stack Overflow corpus yet.
Model association via trait, not inheritance. Attach the package trait to your User (or any tenant model) rather than extending a package model. This keeps your auth model swappable and lets you use the board against Team, Project, or Workspace models without fighting the package.
class User extends Authenticatable
{
use \Vadykoo\TodoBoard\Concerns\HasTodoBoards;
}
Facade for orchestration, models for reads. Use the facade/service for writes that span entities (move a task between columns, reorder, assign) because that is where validation and events live. Use Eloquent queries directly for reads and dashboards — eager-load the relations (->with('tasks.assignee')) so you don't N+1 inside a loop of boards.
Keep status/column logic out of your controllers. A todo board's real complexity is transition rules (can a task go from done back to todo? does moving to done stamp completed_at?). Put those in a small application-level service that wraps the package, so if 1.1.0 changes the transition semantics you patch one class.
final class BoardWorkflow
{
public function __construct(private TodoBoard $board) {}
public function complete(Task $task): void
{
DB::transaction(fn () => $this->board->moveTask($task, 'done'));
// your side effects: notifications, audit log, webhooks
}
}
Wrap multi-step operations in transactions. Reordering and moving tasks typically rewrite a position/order column across sibling rows. Always wrap in DB::transaction() and re-read the column's tasks inside the transaction, or you will get duplicate positions under concurrent drag-and-drop.
Listen to package events rather than overriding internals. If the release ships events (task created/moved/completed), subscribe to them in an EventServiceProvider for notifications, activity feeds, and analytics. This is the supported extension point and survives minor upgrades; subclassing package classes does not.
HTTP layer: if the package registers routes, publish and override them rather than patching vendor files. If you're building an SPA/Inertia front end, use the package's models and a thin JSON controller of your own — don't try to make the Blade views emit JSON.
Seeding and tests. Use the package factories if shipped (TodoBoard::factory()); otherwise create records through the facade so invariants hold. In tests, use RefreshDatabase and assert on the behaviour (task ends in done, completed_at set, event dispatched) rather than on internal column values, which are the most likely thing to shift in 1.x.
create_tasks_table). If you already have a tasks table, either set a table prefix in config or rename the published stub before running. Check migrations/ in the package before php artisan migrate.^1.0 and read the diff on each composer update anyway; first-year packages often ship behaviour changes in minors.auth on its routes is a data leak. Check php artisan route:list --path=todo immediately after install.TaskPolicy/BoardPolicy and apply it in your own controllers or via route middleware; do not rely on the package's default scoping.position values, producing flickering sort order. Add a small artisan command or test that detects and renumbers duplicates.due_date vs due_at semantics are a classic first-release ambiguity. Read the migration and cast definitions; store UTC and render in the user's timezone yourself.php artisan vendor:publish --force to re-inspect stubs, php artisan tinker to drive the facade interactively, and Model::preventLazyLoading() in AppServiceProvider during local dev to surface missing eager loads.1.1.x ships, keep package usage behind your own thin service/facade layer. When 1.1.0 lands you will thank yourself.How can I help you explore Laravel packages today?