{"slug": "the-schema-doctor-is-in", "title": "The schema doctor is in", "summary": "Laravel Truss 1.5 adds truss:doctor, a deterministic, structure-only database schema review with thirteen rules that can fail CI builds, catching issues like unindexed foreign keys and tables without primary keys. The tool, which has nearly 300 Packagist installs and over 70 GitHub stars, exits non-zero on findings and integrates with the dashboard's Health panel.", "body_md": "Laravel\n\n# The schema doctor is in\n\nLaravel Truss 1.5 adds truss:doctor: a deterministic, structure-only review of your database schema, thirteen rules deep, that can fail your CI build.\n\n## Truss series\n\n- 1\n[There's no artisan schema:show, so I built one](/posts/introducing-truss/) - 2 The schema doctor is in\n- 3\n[I gave my schema viewer your app's colours](/posts/gave-my-schema-viewer-your-app-colours/) - 4\n[My coding agent kept inventing columns](/posts/my-coding-agent-kept-inventing-columns/)\n\n[View series →](/series/truss/)\n\nA migration that adds a `user_id`\n\ncolumn with no supporting index passes review every time. It looks fine. Laravel doesn’t complain, the migration runs clean, CI is green. Then a few months later someone’s staring at a JOIN that touches two hundred rows and takes eight seconds, and nobody remembers why.\n\nThat’s the class of problem [Truss](https://github.com/albertoarena/laravel-truss) 1.5 is built to catch before it ships: the schema doctor.\n\nI wrote about [Truss](/posts/introducing-truss/) here in July, a live, zoomable ER diagram of your Laravel app’s actual database schema. It’s picked up more traction than I expected since then: it’s closing in on 300 installs on Packagist and past 70 stars on GitHub, almost entirely word of mouth in the Laravel community. That traction is exactly what pushed the next feature: a diagram is great for seeing your schema, but it doesn’t tell you when something in it is wrong. `truss:doctor`\n\ndoes.\n\n## What it catches\n\nRun it and it flags problems that are visible from structure alone:\n\n- Tables with no primary key\n- Foreign keys with no supporting index\n- Duplicate or redundant indexes\n- Foreign keys whose type doesn’t match the key they reference\n- Money-looking columns stored as\n`float`\n\n- Pivots without a unique key, unindexed\n`deleted_at`\n\n, and more\n\nThirteen rules in total, across integrity, index, and type categories, each with a stable code (like `TRUSS-IDX-001`\n\n) so you can look it up, silence it, or change its severity.\n\nRules are engine-aware where it matters: an unindexed foreign key is an **error** on PostgreSQL and SQLite, but only **info** on MySQL and MariaDB, since those auto-index foreign keys.\n\n## In the terminal and CI\n\n```\nphp artisan truss:doctor\nphp artisan truss:doctor --preset=strict --fail-on=warning\nphp artisan truss:doctor --format=json\n```\n\nIt exits non-zero once a finding hits your fail level, so a migration that introduces a problem fails the build. No AI, no queries, no row data: deterministic and structure-only, safe to run in a commit hook or a CI pipeline against a database you don’t fully trust.\n\n## In the dashboard\n\nThe same findings surface in the dashboard as a new Health panel, the heart icon in the toolbar. Tables with a problem are flagged right on the diagram, the offending column is marked inline, and lower-confidence (heuristic) findings are labelled as such. Same engine, same findings, two front ends depending on whether you’re at a terminal or in the browser.\n\n## Try it\n\nThe [live demo](https://trussphp.com/demo/) has it running against a fictional schema. Open the Health panel and you’ll see a handful of foreign keys flagged for a missing index.\n\n- Live demo:\n[trussphp.com/demo](https://trussphp.com/demo/) - Guide, with every rule code:\n[trussphp.com/guides/schema-doctor](https://trussphp.com/guides/schema-doctor/) - Release notes:\n[v1.5.0 on GitHub](https://github.com/albertoarena/laravel-truss/releases/tag/v1.5.0)\n\nUpdate with `composer update albertoarena/laravel-truss`\n\n, then run `php artisan truss:doctor`\n\nand see what’s already in there.\n\n## What’s next\n\nThis is phase one: the engine and the thirteen rules. Suppression files, more rules, and CI formatters are on the [roadmap](https://trussphp.com/roadmap/). If a rule feels too noisy, too quiet, or there’s a check you’d want that isn’t there yet, the [discussion thread](https://github.com/albertoarena/laravel-truss/discussions/18) is open. I’d love to hear what you run it against.\n\n[Open a discussion on GitHub](https://github.com/albertoarena/laravel-truss/discussions)or\n\n[send me an email](mailto:hello@albertoarena.it).", "url": "https://wpnews.pro/news/the-schema-doctor-is-in", "canonical_source": "https://albertoarena.it/posts/the-schema-doctor-is-in/", "published_at": "2026-07-31 10:00:00+00:00", "updated_at": "2026-08-15 15:11:43.762080+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Laravel Truss", "Packagist", "GitHub", "PostgreSQL", "SQLite", "MySQL", "MariaDB", "albertoarena/laravel-truss"], "alternates": {"html": "https://wpnews.pro/news/the-schema-doctor-is-in", "markdown": "https://wpnews.pro/news/the-schema-doctor-is-in.md", "text": "https://wpnews.pro/news/the-schema-doctor-is-in.txt", "jsonld": "https://wpnews.pro/news/the-schema-doctor-is-in.jsonld"}}