ast-dataflow-schema-audit
Audit assessment
No — the current tool cannot audit the entire Supabase database by itself. It can provide useful application-code column lineage, which could become one input to a broader schema audit.
What it currently covers
• TypeScript .from(‘table’) chains: ◦ Reads through .select(), filters, ordering, .match(), and RPC payloads. ◦ Writes through .insert(), .update(), .upsert(), and .match(). ◦ Reports exact, wildcard, or indirect confidence. • Python under scripts/: ◦ Raw SQL passed to asyncpg-style calls. ◦ supabase-py fluent chains. ◦ SQL parsing via sqlglot when installed, otherwise regex fallback. • Symbol, type, import, re-export, flow, and dead-export analysis for the TypeScript corpus.
Representative results show the limitation: the TypeScript query found 103 estimated references to source_documents.id, while the Python query found one indirect SQL write and reported sqlglot: false in the current environment.
What it cannot currently determine
Foreign keys
It does not:
• Connect to Supabase or query pg_catalog, information_schema, or pg_constraint. • Enumerate actual tables, columns, primary keys, or foreign keys. • Compare declared FKs with generated types or migration history. • Infer with confidence that foo_id should reference foo.id. • Analyse all joins, RPC implementations, views, triggers, or external consumers.
supabase/types/database.types.ts does contain generated Relationships metadata, but the AST tool does not parse that metadata as a schema catalogue. It only benefits from the types indirectly when classifying Supabase clients.
Naming and usage heuristics would also produce false positives. For example, supabase/platform/001_canonical_source_tables.sql explicitly documents reference_items.source_document_id as an intentionally omitted cross-class FK. Static code usage alone cannot distinguish that deliberate design from a missing constraint.
Dead columns
It could identify candidate unused columns, but not prove that a column is safe to remove.
A complete candidate scan would require:
- An external inventory of every table and column.
- One lineage query per column; there is no current all-schema/all-column command.
- Coverage of TypeScript, Python, SQL migrations, database functions, views, triggers, jobs, and other clients.
- Manual treatment of wildcard reads, spreads, dynamic payloads, JSONB keys, and indirect queries.
A zero-result query currently means “no matching static reference was found in the scanned corpus”, not “the database column is dead”. Wildcard selects, dynamic writes, RPC implementations, database-side code, and external consumers can all invalidate that conclusion.
There is also a known gap in the current TypeScript implementation: rpc-payload exists in the write result type but RPC write detection is deferred.
Recommended direction
Build a separate schema-aware schema-audit layer rather than extending the current queries into an unsafe deletion tool:
- Snapshot the live schema, preferably from PostgreSQL catalog queries, including tables, views, columns, PKs, FKs, indexes, functions, triggers, and policies.
- Parse generated Supabase types and migrations as additional provenance, while treating the live catalog as authoritative.
- Expand lineage collection to TypeScript, Python, raw SQL files, SQL functions, views, triggers, and RPC definitions.
- Produce an evidence matrix for each column: ◦ exact application reference ◦ wildcard reference ◦ indirect/dynamic reference ◦ database-side reference ◦ external/unknown usage
- Report likely missing FKs separately from intentional or uncertain relationships.
- Report dead-column candidates only, with no automatic removal.
The committed tool is therefore suitable for application reference discovery and migration impact analysis, but not yet for a trustworthy whole-Supabase schema audit.