- Create bible/ as single source of truth (architecture, API, frontend, installation, usage, security, roadmap) - Verify and fix Bible against actual source code (API methods, endpoints, data flow) - Trim README.md and CLAUDE.md to minimal stubs pointing to the Bible - Remove duplicate claude.md (lowercase) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.5 KiB
4.5 KiB
Architecture
Overview
TurboRFQ follows a thin MVC-like structure: a PHP backend exposes a JSON REST API consumed by a single-page vanilla-JS frontend. There is no ORM — SQL is built generically from information_schema metadata at runtime.
Browser
└── index.html + app.js (Tabulator grid, fetch calls)
│ JSON over HTTP
▼
public/index.php (Slim 4 router + PHP-DI container)
│
├── Db.php — PDO factory (session credentials)
├── MetaService.php — schema / table / column metadata
├── DataService.php — all data operations
└── BackupService.php — mysqldump wrapper
│
▼
MariaDB server (user's own credentials)
Backend Services
Db.php — Database Layer
| Responsibility | Details |
|---|---|
| PDO factory | Creates a PDO instance from credentials stored in the PHP session |
| Connection test | Verifies credentials before storing them in session on login |
| Session auth | Credentials live in $_SESSION; every request re-creates PDO |
Key design decision: no connection pool, no persistent connections. Each API request opens a fresh PDO with the session user's credentials so MariaDB's own permission system is fully enforced.
MetaService.php — Metadata Service
Queries information_schema exclusively — never touches actual table data.
| Method / responsibility | What it does |
|---|---|
| Schema tree | Lists schemas (databases) the user can see → table names within each |
| Column definitions | Reads information_schema.COLUMNS: name, DATA_TYPE, COLUMN_TYPE, COLUMN_KEY, IS_NULLABLE, COLUMN_DEFAULT, EXTRA, COLUMN_COMMENT, ORDINAL_POSITION |
| Primary key detection | Reads COLUMN_KEY = 'PRI' directly from information_schema.COLUMNS |
| Foreign key relationships | Reads information_schema.KEY_COLUMN_USAGE where REFERENCED_TABLE_NAME IS NOT NULL |
| Editor type mapping | Maps DATA_TYPE strings to Tabulator editor types |
DataService.php — Data Service
All operations accept schema, table, and optional filter/pagination parameters.
| Operation | Mechanism |
|---|---|
| SELECT | Parameterized SQL with LIKE %val% filters per column; LIMIT/OFFSET pagination; optional ORDER BY |
| INSERT | Skips auto_increment columns; uses column list from MetaService |
| UPDATE | WHERE clause built from primary key columns only |
| DELETE | WHERE clause built from primary key columns only |
| DELETE batch | Single-column PK: batched WHERE … IN (…) (batch size 500) inside one transaction. Composite PK: row-by-row within one transaction |
| CSV import | Receives pre-parsed rows as a JSON array (CSV parsing is done on the frontend); each row is inserted inside a single transaction; per-row errors are collected without stopping the import |
| CSV export | Runs a full SELECT (filters/sort applied), converts to CSV string using ; delimiter, returns JSON {csv, rowCount} — download is handled on the frontend |
| FK suggestions | Queries referenced table for distinct values; search param filters with LIKE; without search limited to 1000 values |
BackupService.php — Backup Service
Thin wrapper around the mysqldump CLI binary.
| Feature | Detail |
|---|---|
| Scope | Single database or all databases |
| Output | Temporary file streamed to browser as a download |
| Cleanup | Temp file removed after streaming |
Frontend Architecture
See frontend.md for details.
Data Flow — Typical Read Request
- User clicks a table in the sidebar.
app.jscallsGET /api/table/meta?schema=X&table=Y.- Backend:
MetaServicequeriesinformation_schema, returns column definitions + PK info. app.jsbuilds Tabulator column config from metadata.- Tabulator calls
POST /api/table/datawith{schema, table, page, size, filters, sort}in the request body. - Backend:
DataServicebuilds parameterized SELECT, returns{data, total}. - Tabulator renders rows, activates column header filters and pagination.
Data Flow — Typical Write Request
- User edits a cell and clicks Save row.
app.jssendsPOST /api/table/updatewith{schema, table, row, pk}.- Backend:
DataServicebuildsUPDATE … SET … WHERE pk = ?, executes, returns affected rows. - Frontend refreshes the row or shows an error.