Phase 1 Implementation

04 β€” Phase 1 Implementation Plan (MVP)

Back to README | Prev: Database Design | Next: Roadmap


Goal

A user can open SchemaCraft, design tables visually on a canvas, define relationships, preview and export working Laravel migration files.


Build Order β€” 8 Steps

Each step builds on the previous one. The project should be runnable and testable after each step.


Step 1: Project Scaffolding

What: Create the Laravel app and package skeleton.

Tasks:

  1. Create a Laravel 12 app (with Pest) in a temp folder, then move into SchemaCraft/
  2. Install Livewire 4: composer require livewire/livewire
  3. Verify Tailwind CSS 4 + Vite setup (Laravel 12 ships with it)
  4. Add @source "../../packages/schemacraft/resources/views"; to resources/css/app.css so Tailwind scans package views
  5. Create the package directory structure under packages/schemacraft/
  6. Create packages/schemacraft/composer.json with:
    • PSR-4 autoload (SchemaCraft\\ maps to src/)
    • Laravel auto-discovery for the service provider
    • Dependencies: illuminate/support, livewire/livewire
  7. Add path repository to root composer.json and require schemacraft/schemacraft:@dev
  8. Run composer update to symlink the package

Files created/modified:

  • packages/schemacraft/composer.json (new)
  • Root composer.json (modified β€” path repo + require)
  • resources/css/app.css (modified β€” Tailwind source path)

Verify: composer update completes without errors. Package is symlinked in vendor/schemacraft/.


Step 2: Package Foundation

What: Service provider, config, routes, migrations, models, enums, and layout.

Service Provider β€” src/SchemaCraftServiceProvider.php

  • Merges config from config/schemacraft.php
  • Loads routes from routes/web.php (with configurable prefix + middleware)
  • Loads views namespaced as schemacraft::
  • Publishes migrations to host app
  • Registers Livewire components via Livewire::addNamespace('schemacraft', ...)

Config β€” config/schemacraft.php

  • route_prefix (default: schemacraft)
  • middleware (default: ['web'])
  • default_canvas settings (zoom, pan, grid_size, snap_to_grid)
  • default_table settings (width, color)

Routes β€” routes/web.php

Method URI Action
GET /schemacraft ProjectManager Livewire component
GET /schemacraft/project/{project} Canvas designer view
GET /schemacraft/project/{project}/export ZIP download

Migrations (5 files)

All prefixed schemacraft_ β€” see Database Design for full schemas.

Migration Table
2026_01_01_000001_create_schemacraft_projects_table.php schemacraft_projects
2026_01_01_000002_create_schemacraft_tables_table.php schemacraft_tables
2026_01_01_000003_create_schemacraft_columns_table.php schemacraft_columns
2026_01_01_000004_create_schemacraft_relationships_table.php schemacraft_relationships
2026_01_01_000005_create_schemacraft_indexes_table.php schemacraft_indexes

Models (5 files in src/Models/)

Model Key Relationships Casts
Project hasMany tables, hasMany relationships canvas_settings β†’ array, SoftDeletes
Table belongsTo project, hasMany columns, hasMany indexes booleans, decimals
Column belongsTo table enum_values β†’ array, booleans
Relationship belongsTo project, belongsTo sourceTable/targetTable line_points β†’ array
Index belongsTo table column_ids β†’ array

Enums (2 files in src/Enums/)

Enum Values Helper Methods
ColumnType All 30+ Laravel column types requiresLength(), requiresPrecision(), requiresValues()
RelationshipType hasOne, hasMany, belongsTo, belongsToMany, morphOne, morphMany, etc. β€”

Layout β€” resources/views/layouts/app.blade.php

  • Uses @vite() from host app
  • Includes @livewireStyles / @livewireScripts
  • Simple nav bar with "SchemaCraft" branding
  • Renders Livewire component dynamically

Files created:

packages/schemacraft/src/SchemaCraftServiceProvider.php
packages/schemacraft/config/schemacraft.php
packages/schemacraft/routes/web.php
packages/schemacraft/database/migrations/ (5 files)
packages/schemacraft/src/Models/ (5 files β€” Project, Table, Column, Relationship, Index)
packages/schemacraft/src/Enums/ (2 files β€” ColumnType, RelationshipType)
packages/schemacraft/resources/views/layouts/app.blade.php

Verify: php artisan migrate creates all 5 tables. Visit /schemacraft renders the layout.


Step 3: Project Management (CRUD)

What: List, create, rename, and delete projects.

Livewire Component β€” ProjectManager.php

  • Lists all projects in a card grid with pagination
  • Create new project (name + description) via modal
  • Rename project inline
  • Delete project with confirmation
  • Navigate to canvas designer on click

View β€” project-manager.blade.php

  • Card grid showing: project name, description, table count, created date
  • "Create New Project" button opens Alpine.js modal
  • Action buttons per card: Open Designer, Rename, Delete

Files created:

packages/schemacraft/src/Http/Livewire/ProjectManager.php
packages/schemacraft/resources/views/livewire/project-manager.blade.php

Verify: Create, rename, delete projects via the UI. Database records update correctly.


Steps 4 & 5: Canvas + Table Nodes

What: The visual canvas with pan, zoom, drag, and table node rendering. This is the most technically complex step.

Canvas Livewire Component β€” Canvas.php

Method Purpose
mount($project) Loads project with tables, columns, relationships
addTable() Creates new table with offset position
updateTablePosition($tableId, $x, $y) Persists drag result (called from Alpine)
updateCanvasSettings($settings) Persists zoom/pan state
selectTable($tableId) Opens side panel for editing
deselectTable() Closes side panel
deleteTable($tableId) Removes table with cascading deletes

Canvas View β€” canvas.blade.php

Structure:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Toolbar: [Add Table] [Reset View] [Zoom: 100%]    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                             β”‚ Table β”‚
β”‚  SVG Canvas (full viewport)                 β”‚Editor β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                           β”‚ Panel β”‚
β”‚  β”‚  users        β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚(when  β”‚
β”‚  β”‚  id           │────│  posts        β”‚      β”‚select β”‚
β”‚  β”‚  name         β”‚    β”‚  id           β”‚      β”‚ed)   β”‚
β”‚  β”‚  email        β”‚    β”‚  user_id (FK) β”‚      β”‚       β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚  title        β”‚      β”‚       β”‚
β”‚                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚       β”‚
β”‚                                             β”‚       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”˜
  • Full-viewport <div x-data="schemaCanvas(...)"> wrapping an SVG
  • SVG grid background using <pattern> (minor + major grid lines)
  • <g :transform="viewTransform"> applies pan/zoom to all content
  • Table nodes via <template x-for>: white card with colored header, column rows
  • wire:ignore on SVG container prevents Livewire DOM-diffing during drags

Alpine.js schemaCanvas Component (inline in canvas view)

Feature Implementation
Pan mousedown on background starts pan, mousemove updates panX/panY, mouseup persists
Zoom wheel event adjusts zoom (0.2–3.0), zooms toward mouse via getScreenCTM()
Drag tables mousedown on table captures offset, mousemove updates position (snap-to-grid optional), mouseup calls $wire.updateTablePosition()
Dynamic height Computed from column count + built-in fields (id, timestamps, softDeletes)
Livewire sync $wire.$on('table-added', ...) pushes updates into Alpine state

Files created:

packages/schemacraft/src/Http/Livewire/Canvas.php
packages/schemacraft/resources/views/livewire/canvas.blade.php

Verify: Add tables, drag to reposition, refresh page β€” positions persist. Zoom/pan works smoothly at 60fps.


Step 6: Table Editor Panel

What: Side panel for editing table settings and columns.

Livewire Component β€” TableEditor.php

Feature Details
Table name Edit with snake_case validation
Toggle switches use_id, use_timestamps, use_soft_deletes
Color picker Table header color
Add column Name, type (dropdown from ColumnType enum), nullable, default, unique, index
Edit columns Inline editing with wire:model.blur for performance
Remove columns With confirmation
Reorder columns Via sort_order
Delete table With confirmation
Event dispatch table-updated after every change

View β€” table-editor.blade.php

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ Table Editor ──────────────┐
β”‚  Table: [users          ]                  β”‚
β”‚  Color: [β–  #3B82F6]                       β”‚
β”‚                                            β”‚
β”‚  β˜‘ id()  β˜‘ timestamps()  ☐ softDeletes() β”‚
β”‚                                            β”‚
β”‚  ── Columns ──────────────────────────     β”‚
β”‚  name    β”‚ string  β”‚ ☐N ☐U ☐I β”‚ [Γ—]      β”‚
β”‚  email   β”‚ string  β”‚ β˜‘N ☐U β˜‘I β”‚ [Γ—]      β”‚
β”‚  bio     β”‚ text    β”‚ β˜‘N ☐U ☐I β”‚ [Γ—]      β”‚
β”‚                                            β”‚
β”‚  ── Add Column ───────────────────────     β”‚
β”‚  Name:  [____________]                     β”‚
β”‚  Type:  [string     β–Ό]                     β”‚
β”‚  [☐ Nullable] [☐ Unique] [☐ Index]       β”‚
β”‚  [+ Add Column]                            β”‚
β”‚                                            β”‚
β”‚  [πŸ—‘ Delete Table]                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Right-side sliding panel (w-96, full height)
  • Table settings section at top
  • Scrollable column list in middle
  • "Add Column" form at bottom

Files created:

packages/schemacraft/src/Http/Livewire/TableEditor.php
packages/schemacraft/resources/views/livewire/table-editor.blade.php

Verify: Click table to open editor. Add/edit/remove columns. Canvas table node updates to show changes.


Step 7: Relationships

What: Draw relationships between tables with auto FK creation and SVG lines.

User Flow

  1. Click "Draw Relationship" button in toolbar (enters relationship mode)
  2. Click source table β€” highlight appears
  3. Click target table β€” modal opens for type selection
  4. Select type (hasOne, hasMany, belongsTo, belongsToMany) + on_delete action
  5. System auto-creates FK column on the correct table
  6. SVG line appears between the two tables with cardinality indicators

RelationshipManager Component β€” RelationshipManager.php

Method Purpose
createRelationship($sourceId, $targetId, $type) Creates relationship + auto-creates FK column
deleteRelationship($id) Removes relationship and optionally the FK column
List/edit Manage existing relationships

FK Column Placement Logic:

Relationship Type FK Goes On Example
belongsTo Source table posts.user_id
hasOne / hasMany Target table phones.user_id
belongsToMany Pivot table No FK on either table directly

SVG Relationship Lines (in canvas view)

  • Lines rendered as <line> or <path> between table nodes
  • Coordinates computed from table positions (midpoints of nearest edges)
  • SVG <marker> definitions for cardinality:
    • "1" side β†’ vertical line (|)
    • "Many" side β†’ crow's foot (three fanning lines)

Files created:

packages/schemacraft/src/Http/Livewire/RelationshipManager.php
packages/schemacraft/resources/views/livewire/relationship-manager.blade.php

Verify: Draw relationships. Lines appear on canvas. FK columns auto-created. Cardinality indicators visible.


Step 8: Code Generation + Export

What: Generate valid Laravel migrations and export as ZIP.

MigrationGenerator β€” src/Generators/MigrationGenerator.php

Pure PHP class with no HTTP/Livewire dependency.

Method Purpose
generateForProject(Project $project): array Returns ['filename.php' => 'content']

Generates:

  • All 30+ column types with correct parameters (length, precision, enum values)
  • All modifiers: nullable, default, unique, index, unsigned, comment
  • Foreign key constraints with cascadeOnDelete
  • id(), timestamps(), softDeletes() shortcuts
  • Pivot table migrations for belongsToMany relationships
  • Proper down() methods with Schema::dropIfExists()

CodePreview Component β€” src/Http/Livewire/CodePreview.php

  • Shows generated migration code in a tabbed viewer
  • File tabs on left, syntax-highlighted code on right
  • Uses MigrationGenerator to produce output

SchemaExportService β€” src/Services/SchemaExportService.php

  • Creates a ZIP file containing database/migrations/ folder
  • Uses PHP's ZipArchive extension

ExportController β€” src/Http/Controllers/ExportController.php

  • download($project) β€” generates ZIP, returns download response, deletes temp file

Files created:

packages/schemacraft/src/Generators/MigrationGenerator.php
packages/schemacraft/src/Services/SchemaExportService.php
packages/schemacraft/src/Http/Controllers/ExportController.php
packages/schemacraft/src/Http/Livewire/CodePreview.php
packages/schemacraft/resources/views/livewire/code-preview.blade.php

Verify: Click "Preview Code" β€” see generated migrations. Click "Export" β€” download ZIP. Unzip contains valid Laravel migration syntax.


Complete File Manifest (30 files)

packages/schemacraft/
β”œβ”€β”€ composer.json
β”œβ”€β”€ config/
β”‚   └── schemacraft.php
β”œβ”€β”€ database/migrations/
β”‚   β”œβ”€β”€ 2026_01_01_000001_create_schemacraft_projects_table.php
β”‚   β”œβ”€β”€ 2026_01_01_000002_create_schemacraft_tables_table.php
β”‚   β”œβ”€β”€ 2026_01_01_000003_create_schemacraft_columns_table.php
β”‚   β”œβ”€β”€ 2026_01_01_000004_create_schemacraft_relationships_table.php
β”‚   └── 2026_01_01_000005_create_schemacraft_indexes_table.php
β”œβ”€β”€ resources/views/
β”‚   β”œβ”€β”€ layouts/
β”‚   β”‚   └── app.blade.php
β”‚   └── livewire/
β”‚       β”œβ”€β”€ canvas.blade.php
β”‚       β”œβ”€β”€ code-preview.blade.php
β”‚       β”œβ”€β”€ project-manager.blade.php
β”‚       β”œβ”€β”€ relationship-manager.blade.php
β”‚       └── table-editor.blade.php
β”œβ”€β”€ routes/
β”‚   └── web.php
└── src/
    β”œβ”€β”€ SchemaCraftServiceProvider.php
    β”œβ”€β”€ Enums/
    β”‚   β”œβ”€β”€ ColumnType.php
    β”‚   └── RelationshipType.php
    β”œβ”€β”€ Generators/
    β”‚   └── MigrationGenerator.php
    β”œβ”€β”€ Http/
    β”‚   β”œβ”€β”€ Controllers/
    β”‚   β”‚   └── ExportController.php
    β”‚   └── Livewire/
    β”‚       β”œβ”€β”€ Canvas.php
    β”‚       β”œβ”€β”€ CodePreview.php
    β”‚       β”œβ”€β”€ ProjectManager.php
    β”‚       β”œβ”€β”€ RelationshipManager.php
    β”‚       └── TableEditor.php
    β”œβ”€β”€ Models/
    β”‚   β”œβ”€β”€ Column.php
    β”‚   β”œβ”€β”€ Index.php
    β”‚   β”œβ”€β”€ Project.php
    β”‚   β”œβ”€β”€ Relationship.php
    β”‚   └── Table.php
    └── Services/
        └── SchemaExportService.php

Verification Checklist

Run these checks after completing each step:

After Step Test
1 composer update β€” package symlinks without errors
2 php artisan migrate β€” 5 tables created. /schemacraft renders layout
3 Create, rename, delete projects via UI. Database records correct
4-5 Add tables, drag to reposition, refresh β€” positions persist. Zoom/pan smooth
6 Click table β†’ editor opens. Add/edit/remove columns. Canvas updates
7 Draw relationships. Lines appear. FK columns auto-created. Cardinality visible
8 Preview code β€” valid migrations. Export ZIP β€” contains migration files

End-to-End Test

Design a small schema: users, posts, comments, tags (with pivot). Export migrations, paste into a fresh Laravel app, run php artisan migrate β€” all tables created correctly with foreign keys.


Next: Roadmap

Loading...