Flowforge Documentation

repository·4.x·Indexed 19 days ago

https://github.com/relaticle/flowforge

A Laravel package that transforms Eloquent models into drag-and-drop Kanban boards. It integrates with Filament admin panels or works as standalone Livewire components. Key features include the flowforge:make-board Artisan command, position management via the ext-bcmath extension, and support for PHP 8.3+, Laravel 12+, and Filament 5.x.

Tokens
25.2K
Snippets
88
Records
103
Agent score
63%

What's inside Flowforge

  1. Overview of Flowforge Kanban Boards

    4.x

    Flowforge is a tool designed to transform any Laravel model into a production-ready, drag-and-drop Kanban board. It is built to work seamlessly within Filament admin panels or as standalone Livewire components.

    Key capabilities include:

    • Enterprise-Scale Performance: Uses cursor-based pagination to handle unlimited cards per column with optimized position-based ordering.
    • Flexible Integration: Supports three patterns: Filament Pages, Resource integration, or standalone Livewire components.
    • Rich Card Schemas: Leverages the Filament Schema builder to create complex card layouts containing forms, components, and dynamic content.
    • Smart Position Management: Features an advanced ranking algorithm for drag-and-drop ordering with automatic conflict resolution and repair commands.
    • Optimistic UI: Provides instant visual feedback, loading states, and smooth scrolling for a responsive user experience.
    • Native Filament Integration: Deeply integrates with Filament's table system for filters, search, and actions.
  2. Follow the Flowforge naming convention (Modified BEM)

    4.x

    Flowforge uses a modified BEM (Block Element Modifier) methodology for all custom CSS classes. All custom classes must be prefixed with ff- to avoid collisions.

    Syntax: .ff-[block]__[element]--[modifier]

    • Block: The standalone component (e.g., .ff-card).
    • Element: A part of the block, separated by double underscores (e.g., .ff-card__title).
    • Modifier: A variation of the block or element, separated by double dashes (e.g., .ff-card--priority-high).

    Rules:

    1. Use kebab-case for all class names.
    2. Use descriptive, semantic names.
    3. Always prefix with ff-.
    <!-- Example of BEM structure -->
    <div class="ff-card ff-card--priority-high">
        <div class="ff-card__body">
            <h4 class="ff-card__title">Card Title</h4>
        </div>
    </div>
  3. Understand Flowforge concurrency and safety mechanisms

    4.x

    Flowforge implements several mechanisms to ensure data integrity during concurrent drag-and-drop operations:

    • Jitter Mechanism: The DecimalPosition::between() method adds ±5% random jitter to calculations, preventing multiple users from generating identical positions simultaneously.
    • Auto-Rebalancing: If the gap between adjacent cards falls below 0.0001, positions are automatically redistributed with 65535 spacing during card moves.
    • Retry Mechanism: If a unique constraint violation occurs (on [status, position]), Flowforge automatically retries the operation up to 3 times with exponential backoff (50ms, 100ms, 200ms). This is supported on SQLite, MySQL, and PostgreSQL.
  4. Implement responsive design with Tailwind breakpoints

    4.x

    Flowforge follows a mobile-first approach. While most components have built-in responsive behavior, you can use Tailwind's responsive prefixes directly in your markup for custom adjustments.

    Supported Breakpoints:

    • sm: 640px +
    • md: 768px +
    • lg: 1024px +
    • xl: 1280px +
    • 2xl: 1536px +
  5. Integrate Flowforge into a Filament Resource

    4.x

    To add a Kanban view to an existing Filament resource (e.g., viewing tasks within a specific Campaign), extend BoardResourcePage.

    1. Set the $resource property to your target resource class.
    2. Use $this->getRecord() within the board() method to scope the query to the specific resource instance.
    3. Register the new page in the resource's getPages() method.
    namespace App\Filament\Resources\CampaignResource\Pages;
    
    use App\Filament\Resources\CampaignResource;
    use Relaticle\Flowforge\Board;
    use Relaticle\Flowforge\BoardResourcePage;
    use Relaticle\Flowforge\Column;
    
    class CampaignTaskBoard extends BoardResourcePage
    {
        protected static string $resource = CampaignResource::class;
        
        public function board(Board $board): Board
        {
            return $board
                ->query(
                    $this->getRecord()
                        ->tasks()
                        ->whereHas('team', fn($q) => $q->where('id', auth()->user()->current_team_id))
                        ->getQuery()
                )
                ->columnIdentifier('status')
                ->positionIdentifier('position')
                ->columns([
                    Column::make('backlog')->label('Backlog')->color('gray'),
                    Column::make('in_progress')->label('In Progress')->color('blue'),
                    Column::make('review')->label('Review')->color('amber'),
                    Column::make('completed')->label('Completed')->color('green'),
                ]);
        }
    }
    
    // In CampaignResource.php
    public static function getPages(): array
    {
        return [
            'index' => Pages\ListCampaigns::route('/'),
            'create' => Pages\CreateCampaign::route('/create'),
            'edit' => Pages\EditCampaign::route('/{record}/edit'),
            'tasks' => Pages\CampaignTaskBoard::route('/{record}/tasks'),
        ];
    }
  6. Preserve existing order during v2.x to v3.x migration

    4.x

    To prevent losing the current order of items when migrating from string-based positions (v2.x) to decimal-based positions (v3.x), follow this pattern in a Laravel migration:

    1. Add a temporary decimal column (e.g., position_new).
    2. Iterate through distinct status groups.
    3. For each group, order by the original position column and calculate new decimal positions using DecimalPosition::forEmptyColumn() and DecimalPosition::after($lastPosition).
    4. Update the temporary column with these values.
    5. Drop the old position column and rename position_new to position.
    6. Add a unique constraint on ['status', 'position'].
    // Example logic for preserving order
    foreach ($statuses as $status) {
        $tasks = DB::table('tasks')
            ->where('status', $status)
            ->orderBy('position')
            ->get();
    
        $lastPosition = null;
        foreach ($tasks as $task) {
            $newPosition = $lastPosition === null
                ? DecimalPosition::forEmptyColumn()
                : DecimalPosition::after($lastPosition);
    
            DB::table('tasks')
                ->where('id', $task->id)
                ->update(['position_new' => $newPosition]);
    
            $lastPosition = $newPosition;
        }
    }
  7. Integrate Flowforge as a Filament Page

    4.x

    Use the BoardPage class to create a dedicated Kanban page within your Filament admin panel. This provides full Filament integration, automatic registration, and built-in actions.

    namespace App\Filament\Pages;
    
    use App\Models\Task;
    use Relaticle\Flowforge\Board;
    use Relaticle\Flowforge\BoardPage;
    use Relaticle\Flowforge\Column;
    
    class TaskBoard extends BoardPage
    {
        protected static ?string $navigationIcon = 'heroicon-o-view-columns';
        
        public function board(Board $board): Board
        {
            return $board
                ->query(Task::query())
                ->columnIdentifier('status')
                ->positionIdentifier('position')
                ->columns([
                    Column::make('todo')->label('To Do')->color('gray'),
                    Column::make('in_progress')->label('In Progress')->color('blue'),
                    Column::make('completed')->label('Completed')->color('green'),
                ]);
        }
    }
  8. Configure required database fields for Kanban functionality

    4.x

    To enable Flowforge Kanban features (like drag-and-drop ordering), your database table must include a status column (to identify the Kanban column) and a position column (to handle ordering). Use the flowforgePositionColumn() method in your migration to create the specialized position column.

    Schema::create('tasks', function (Blueprint $table) {
        $table->id();
        $table->string('title');                         // Card title
        $table->string('status');                        // Column identifier
        $table->flowforgePositionColumn();               // Drag-and-drop ordering
        $table->timestamps();
    });
  9. Migrate an existing table to support Flowforge

    4.x

    To add Flowforge support to an existing table, create a migration that adds the position column. It is highly recommended to add a unique constraint on [status, position] to enable Flowforge's retry mechanism for concurrent operations.

    <?php
    
    use Illuminate\Database\Migrations\Migration;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Support\Facades\Schema;
    
    return new class extends Migration
    {
        public function up(): void
        {
            Schema::table('tasks', function (Blueprint $table) {
                $table->flowforgePositionColumn('position');
    
                // Recommended: Add unique constraint for concurrent safety
                $table->unique(['status', 'position'], 'unique_position_per_column');
            });
        }
    
        public function down(): void
        {
            $table->dropUnique('unique_position_per_column');
            $table->dropColumn('position');
        }
    };
  10. Quick Start guide for contributing to Flowforge

    4.x

    To contribute to Flowforge, follow these steps:

    1. Fork the repository.
    2. Create a feature branch.
    3. Make your changes.
    4. Run tests using composer test.
    5. Submit a pull request.

    When contributing, follow these guidelines:

    • Adhere to the existing code style.
    • Include tests for any new features.
    • Update documentation to reflect changes.
    • Ensure each pull request focuses on a single feature.
  11. Migrate from Flowforge v2.x to v3.x

    4.x

    Upgrading from v2.x to v3.x involves moving from Lexorank/string-based positions to DecimalPosition/DECIMAL-based positions.

    Breaking Changes

    • PHP Extension: ext-bcmath is now required.
    • Database Schema: The position column type changes from VARCHAR to DECIMAL(20,10).
    • Service Replacement: The Rank service is replaced by DecimalPosition.
    • Laravel Requirement: Requires Laravel 12+.

    Migration Workflow

    1. Verify BCMath: Ensure ext-bcmath is installed via php -m | grep bcmath.
    2. Update Dependencies: Run composer require relaticle/flowforge:^3.0.
    3. Update Database: Create a migration to change the position column type. You can either drop and recreate the column (losing order) or use a custom migration to preserve existing order.
    4. Regenerate Positions: Run php artisan flowforge:repair-positions and select the "regenerate" strategy.
    5. Update Code: Replace all Relaticle\Flowforge\Services\Rank references with Relaticle\Flowforge\Services\DecimalPosition and update method calls (see API changes).
    composer require relaticle/flowforge:^3.0