docs(claude): codify MySQL-only policy for Crewli (WS-6)
CLAUDE.md's existing "Database" subsection is expanded to spell out that MySQL 8.0 is the exclusive database engine for dev, testing, and production. SQLite is forbidden — its quirks (rebuild-on-FK-add cascade behaviour, JSON key-order non-determinism on round-trip, VARCHAR length enforcement gaps, concurrency model) mask bugs that would surface in production MySQL. Context: WS-6 session 2.5 had to omit a FK constraint due to an SQLite-only quirk; session 2.6 (Task 1+2 of this branch) moved test infrastructure to MySQL and restored the FK. This policy ensures the issue cannot recur. Includes the cross-engine query-rewrite rules the migration surfaced (information_schema.STATISTICS over sqlite_master, assertEquals over assertSame on JSON-derived data). Refs: RFC-WS-6.md v1.1, WS-6 session 2.5 deviation #1, session 2.6 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
23
CLAUDE.md
23
CLAUDE.md
@@ -81,6 +81,29 @@ Configure two frontend origins in both Laravel (`config/cors.php` via env) and t
|
||||
|
||||
### Database
|
||||
|
||||
Crewli uses **MySQL 8.0 exclusively** across all environments:
|
||||
|
||||
- **Local development**: MySQL 8.0 via `docker-compose.yml` (`bm_mysql` container, port 3306). Run `make services` to start.
|
||||
- **Testing**: MySQL 8.0 via the same Docker container, separate `crewli_test` database. Run `make test-db-create` once, then `make test`.
|
||||
- **Staging/production**: MySQL 8.0 on the deployment VPS.
|
||||
|
||||
**SQLite is forbidden** in all environments. Reasons:
|
||||
|
||||
- SQLite has known quirks around foreign-key constraints (rebuild-on-FK-add cascades), JSON queries (key-order non-determinism on round-trip differs from MySQL), and concurrent writes that mask bugs which MySQL would surface in production
|
||||
- Cross-database query syntax differences cause silent test/production drift (e.g. `sqlite_master` vs. `information_schema`, VARCHAR length enforcement)
|
||||
- Crewli's enterprise-grade product philosophy doesn't tolerate "but it works on SQLite" as a passing test
|
||||
|
||||
If a contributor finds SQLite references in `phpunit.xml`, `.env.testing`, or any config file, treat it as a regression and fix immediately.
|
||||
|
||||
When writing migrations or queries:
|
||||
|
||||
- Use Laravel's query builder where possible — it handles cross-DB syntax consistently
|
||||
- For raw SQL, write MySQL syntax (no need for SQLite fallbacks). Index introspection: query `information_schema.STATISTICS`, never `sqlite_master`.
|
||||
- Foreign keys go on every relation column. The `nullOnDelete` / `cascadeOnDelete` choice is per the relationship's domain semantics; "no FK" is not an option.
|
||||
- Tests that round-trip JSON data via MySQL JSON columns must use `assertEquals` (structural equality) rather than `assertSame` on associative arrays — MySQL JSON may reorder object keys.
|
||||
|
||||
Other database rules:
|
||||
|
||||
- Primary keys: ULID via `HasUlids` (not UUID v4, not auto-increment on business tables)
|
||||
- Create migrations in dependency order: foundation first, then dependent tables
|
||||
- Always add composite indexes as documented in the design document (section 3.5)
|
||||
|
||||
Reference in New Issue
Block a user