Skip to content

Commit ea217ca

Browse files
authored
Merge pull request #198 from fleetbase/feature/template-builder-system
feat: add reusable template builder system
2 parents de08fa6 + 088793e commit ea217ca

File tree

13 files changed

+1564
-2
lines changed

13 files changed

+1564
-2
lines changed

composer.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@
5555
"spatie/laravel-schedule-monitor": "^3.7",
5656
"spatie/laravel-sluggable": "^3.5",
5757
"sqids/sqids": "^0.4.1",
58-
"xantios/mimey": "^2.2.0"
58+
"xantios/mimey": "^2.2.0",
59+
"spatie/laravel-pdf": "^1.9",
60+
"mossadal/math-parser": "^1.3"
5961
},
6062
"require-dev": {
6163
"friendsofphp/php-cs-fixer": "^3.34.1",
@@ -105,4 +107,4 @@
105107
"@test:unit"
106108
]
107109
}
108-
}
110+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration {
8+
/**
9+
* Run the migrations.
10+
*/
11+
public function up(): void
12+
{
13+
Schema::create('templates', function (Blueprint $table) {
14+
$table->bigIncrements('id');
15+
$table->string('uuid', 191)->unique()->nullable();
16+
$table->string('public_id', 191)->unique()->nullable();
17+
$table->string('company_uuid', 191)->nullable()->index();
18+
$table->string('created_by_uuid', 191)->nullable()->index();
19+
$table->string('updated_by_uuid', 191)->nullable()->index();
20+
21+
// Identity
22+
$table->string('name');
23+
$table->text('description')->nullable();
24+
25+
// Context type — defines which Fleetbase model this template is designed for.
26+
// e.g. 'order', 'invoice', 'transaction', 'shipping_label', 'receipt', 'report'
27+
$table->string('context_type')->default('generic')->index();
28+
29+
// Canvas dimensions (in mm by default, configurable via unit)
30+
$table->string('unit')->default('mm'); // mm, px, in
31+
$table->decimal('width', 10, 4)->default(210); // A4 width
32+
$table->decimal('height', 10, 4)->default(297); // A4 height
33+
$table->string('orientation')->default('portrait'); // portrait | landscape
34+
35+
// Page settings
36+
$table->json('margins')->nullable(); // { top, right, bottom, left }
37+
$table->string('background_color')->nullable();
38+
$table->string('background_image_uuid')->nullable();
39+
40+
// The full template content — array of element objects
41+
$table->longText('content')->nullable(); // JSON array of TemplateElement objects
42+
43+
// Element type definitions / schema overrides (optional per-template customisation)
44+
$table->json('element_schemas')->nullable();
45+
46+
// Status
47+
$table->boolean('is_default')->default(false);
48+
$table->boolean('is_system')->default(false);
49+
$table->boolean('is_public')->default(false);
50+
51+
$table->timestamps();
52+
$table->softDeletes();
53+
54+
// Foreign keys
55+
$table->foreign('company_uuid')->references('uuid')->on('companies')->onDelete('cascade');
56+
$table->foreign('created_by_uuid')->references('uuid')->on('users')->onDelete('set null');
57+
$table->foreign('updated_by_uuid')->references('uuid')->on('users')->onDelete('set null');
58+
59+
// Composite indexes
60+
$table->index(['company_uuid', 'context_type']);
61+
$table->index(['company_uuid', 'is_default']);
62+
});
63+
}
64+
65+
/**
66+
* Reverse the migrations.
67+
*/
68+
public function down(): void
69+
{
70+
Schema::dropIfExists('templates');
71+
}
72+
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration {
8+
/**
9+
* Run the migrations.
10+
*/
11+
public function up(): void
12+
{
13+
Schema::create('template_queries', function (Blueprint $table) {
14+
$table->bigIncrements('id');
15+
$table->string('uuid', 191)->unique()->nullable();
16+
$table->string('public_id', 191)->unique()->nullable();
17+
$table->string('company_uuid', 191)->nullable()->index();
18+
$table->string('template_uuid', 191)->nullable()->index();
19+
$table->string('created_by_uuid', 191)->nullable()->index();
20+
21+
// The fully-qualified model class this query targets
22+
// e.g. 'Fleetbase\Models\Order', 'Fleetbase\FleetOps\Models\Order'
23+
$table->string('model_type');
24+
25+
// The variable name used in the template to access this collection
26+
// e.g. 'orders', 'transactions', 'invoices'
27+
$table->string('variable_name');
28+
29+
// Human-readable label shown in the variable picker
30+
$table->string('label')->nullable();
31+
32+
// JSON array of filter condition groups
33+
// Each condition: { field, operator, value, type }
34+
$table->json('conditions')->nullable();
35+
36+
// JSON array of sort directives: [{ field, direction }]
37+
$table->json('sort')->nullable();
38+
39+
// Maximum number of records to return (null = no limit)
40+
$table->unsignedInteger('limit')->nullable();
41+
42+
// Which relationships to eager-load on the result set
43+
$table->json('with')->nullable();
44+
45+
$table->timestamps();
46+
$table->softDeletes();
47+
48+
$table->foreign('company_uuid')->references('uuid')->on('companies')->onDelete('cascade');
49+
$table->foreign('template_uuid')->references('uuid')->on('templates')->onDelete('cascade');
50+
$table->foreign('created_by_uuid')->references('uuid')->on('users')->onDelete('set null');
51+
});
52+
}
53+
54+
/**
55+
* Reverse the migrations.
56+
*/
57+
public function down(): void
58+
{
59+
Schema::dropIfExists('template_queries');
60+
}
61+
};

0 commit comments

Comments
 (0)