L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Documents · SKILL.md

schema-diagram

schema-diagram

Generates a self-contained interactive ERD document from a Laravel project's live database — a single standalone HTML file with domain-coloured table cards, foreign-key edges anchored to the actual columns, search across tables and columns, a per-table inspector showing both directions of every relation, and a committed JSON schema payload that makes schema…

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: schema-diagram metadata: compatible_agents: [claude-code] tags: [erd, database, schema, documentation, diagram, react-flow, architecture] description: > Generates a self-contained interactive ERD document from a Laravel project's live database — a single standalone HTML file with domain-coloured table cards, foreign-key edges anchored to the actual columns, search across tables and columns, a per-table inspector showing both directions of every relation, and a committed JSON schema payload that makes schema drift reviewable in a diff. Use this skill whenever the user asks to draw, generate, refresh or document a database schema — "generate an ERD", "buat ERD", "draw the database diagram", "visualise my schema", "document the database", "lukis rajah pangkalan data", "update the ERD", "refresh the schema diagram", "erd dah lapuk", "diagram untuk database", "show table relationships", "map my tables to domains", or "what references this table". Reads the live schema by introspection, never by parsing migrations. Does NOT cover designing or writing migrations (project-laravel), domain boundary discovery (project-ddd), or the wider docs tree (project-docs).

Schema diagram

Produces one file: docs/03-architecture/03-database-erd.html. It opens off a filesystem, on a plane, with no network and no toolchain — and it draws every table, column, index and foreign key in the database.

The shape of it

PieceLives inNeedsCommitted
Schema extractorapp/Support/Erd/ErdSchema.php + app/Console/Commands/GenerateErdCommand.phpA migrated database—
Domain mapapp/Support/Erd/ErdDomains.phpA human—
Payloaddocs/03-architecture/erd-schema.json—Yes
Diagram appresources/js/erd/ (React Flow island)——
Coverage teststests/Feature/Docs/ErdDomainCoverageTest.php——
Documentdocs/03-architecture/03-database-erd.htmlNodeYes
Companion pagedocs/03-architecture/03-database-erd.md—Yes
php artisan docs:erd    # database -> JSON   (needs a DB, no Node)
npm run build:erd       # JSON     -> HTML   (needs Node, no DB)

The split is the design. Either half runs alone, and the committed JSON means the document rebuilds on a machine that has never seen the database.

The three rules

1. Read the database, never the migrations. Migrations are the instructions; only the database is the result. A mature project's migration folder is full of column changes, index swaps, renames and drops whose net effect is exactly what a parser gets wrong — silently.

2. Every table gets a domain, assigned by a person. A prefix heuristic mis-files tables and gives no sign that it did. The generator refuses to write when the map has a gap in either direction. That friction is the feature; do not add a default => arm to make it pass.

3. Commit both outputs. The JSON so schema drift shows up in a pull request diff. The HTML so a reader needs nothing but a browser.

Workflow

1. Confirm the ground

php artisan migrate:status | tail -5     # is the schema at head?

A diagram of a half-migrated schema is worse than none. But do not migrate someone's dev database to build a document — that is a side effect they did not ask for, and it can be destructive. Build in a throwaway instead, and drop it:

mysql -e "CREATE DATABASE erd_tmp"
DB_DATABASE=erd_tmp php artisan migrate --force
DB_DATABASE=erd_tmp php artisan docs:erd
mysql -e "DROP DATABASE erd_tmp"

Say plainly in the summary that you did this and that their database is untouched. The About panel records the migration head it was read at, so the document proves its own provenance.

2. Build the domain map first

This is the only part that takes judgement, and everything else is mechanical once it exists. Read references/domain-map.md. Draft it from the code, then correct it by hand:

ls database/migrations | sed 's/^[0-9_]*//;s/\.php$//' | sort
ls app/Models

Aim for 8–14 domains named after the product's own nouns — never layers. Framework and package tables (cache, jobs, sessions, media, telescope_*) all go in one system domain that starts switched off.

Show the user the proposed map before writing it. Getting deployment_mail_sandboxes filed under Data Services rather than Deployment is a decision they own.

3. Scaffold the extractor

references/schema-extractor.md has both PHP files verbatim. Copy them, then run:

php artisan docs:erd

It will fail listing unmapped tables. That is the gate working — fill them in and re-run.

4. Scaffold the diagram app

references/diagram-app.md (seven modules) and references/diagram-styles.md (the stylesheet). Copy verbatim, then change exactly two things: PRODUCT in ErdBoard.jsx and About.jsx, and the brand faces at the top of erd.css.

Rewrite the prose in About.jsx for the product. It is the only writing in the document and the first thing anyone reads.

5. Build and check

npm i @xyflow/react @dagrejs/dagre react react-dom
npm i -D @vitejs/plugin-react vite
npm run build:erd
open docs/03-architecture/03-database-erd.html

Verify before calling it done — see the checklist below.

6. Write the companion page

A 1 MB generated HTML file is not readable in a pull request, does not appear in a grep, and does not render on GitHub. Write docs/03-architecture/03-database-erd.md beside it: a link, the four figures, the domain table with per-domain counts, what it does not draw, the two regeneration commands, and a source-file table. That page is what the docs tree indexes and what a reviewer actually reads.

7. Pin it with tests

references/coverage-tests.md. docs:erd --check protects the document; the suite protects the repository — it fails on the pull request that adds the table, not six weeks later.

- run: php artisan docs:erd --check

Refreshing an existing diagram

php artisan migrate
php artisan docs:erd     # fails if a new table has no domain — add it
npm run build:erd
php artisan test --filter=ErdDomainCoverage
git add docs/03-architecture/erd-schema.json docs/03-architecture/03-database-erd.html

Regenerating the JSON and forgetting the HTML leaves a document confidently showing last month's schema. Check both files are staged.

Verify before calling it done

Open the file and confirm each of these. Every failure here renders successfully and is wrong, which is why the list exists.

  • Edges exist at all. Every card drawing perfectly with zero edges is the signature of a node given width/height instead of initialWidth/initialHeight — React Flow skips measurement, handle bounds never exist, and each edge is dropped in silence.
  • Screenshot before believing a JS assertion. An unpainted Chrome tab throttles ResizeObserver and rAF, so nodes stay hidden and fitView never lands — a healthy page reports as broken, with exactly the symptoms of the bug above.
  • Edges land on rows, not corners. In LR, a foreign key must leave the row holding it and arrive at the row it references. If edges anchor mid-card, handles moved without useUpdateNodeInternals.
  • Switch detail Names → Keys → All. Edge count must not drop. An edge naming a handle that is no longer drawn is deleted silently.
  • The relation count in the header matches stats.relations with all domains on.
  • Flip direction, then theme. Both re-anchor and re-colour without a reload.
  • Search a column name, not a table name. The hit's row is highlighted even at Keys.
  • Click the busiest table. The inspector lists Referenced by — the half no row can tell you — and the numbers are non-zero.
  • The file opens from file://, with the network off. No console error, no blank canvas.
  • The footer names the migration head. That line is what tells a reader in six months whether to trust the picture.

Judgement calls worth getting right

  • A table with no arrows is not an island. Only declared foreign keys become edges; a relation living in an Eloquent method has nothing in the schema to draw. Say so in About rather than inventing edges.
  • Polymorphic pairs get a tag, never an edge. auditable_type + auditable_id resolve at runtime; an arrow to any one table is a claim the schema does not make.
  • A hundred tables cannot be legible at any zoom. That is arithmetic, not a layout defect. Fix what the reader meets first — open on the legend, and let the filters be the way in.
  • system starts off. Cache, queue, sessions and Telescope are plumbing, and most of them join to nothing but fog.
  • Do not reach for a package. beyondcode/laravel-er-diagram-generator and friends read Eloquent relations and emit a static image — no search, no inspector, no domains, and a picture that cannot answer "what references this table".

Anti-patterns

Don'tDo
Parse database/migrationsIntrospect via Schema::getTables()
Infer domains from table-name prefixesAn explicit map, plus a build that fails on a gap
default => 'system' in the domain mapLet the gate fail; add the table deliberately
Fetch the JSON at runtimeInline it — file:// refuses cross-origin
Link a CDN or a webfontInline everything; declare fonts brand-first with a system fallback
width/height on a nodeinitialWidth/initialHeight — the box is seeded and still measured
Migrate the user's dev DB to build a docBuild in a throwaway database, drop it, say so
fitView on a setTimeoutuseNodesInitialized — the event, not a guess
Re-derive nodes when selection changesPaint state onto the nodes already in state
Commit only the HTMLCommit the JSON too — it is the reviewable diff
Leave the HTML as the only docWrite the companion .md — the HTML is not reviewable or greppable
Ship a static PNG/SVG "for simplicity"It cannot answer the one question people open an ERD to ask

Reference Files

FileContents
references/schema-extractor.mdErdSchema + GenerateErdCommand verbatim, the payload shape, and the five introspection traps (server-wide getTables(), sentinel migrations, MySQL type noise, morphs, FK-less tables)
references/domain-map.mdErdDomains template, how to choose 8–14 domains, the tested 13-colour palette, and the two-way coverage gate
references/diagram-app.mdAll seven resources/js/erd/ modules verbatim, the five silent React Flow failure modes, the browser-throttling trap, and the interaction model
references/diagram-styles.mderd.css verbatim — dark/light token blocks, node geometry that must agree with geometry.js
references/build-pipeline.mdbuild.mjs verbatim, why one standalone file, the two escaping traps, dependencies, dev loop, and CI
references/coverage-tests.mdThe Pest suite that pins domain coverage, legend completeness, payload shape and morph handling — plus why it must filter on getCurrentSchemaName() to work on SQLite
Skills enregistrées