GRAPH_REPORT — Car Dealership Knowledge Graph
Run Summary
| Field |
Value |
| Date |
2026-05-06 |
| Project |
car-dealership |
| Stack |
Next.js 15 App Router, TypeScript, Supabase, Tailwind CSS, shadcn/ui |
| Corpus |
~230 files (TypeScript/TSX, SQL, Markdown, JSON, images) |
| Graph |
43 nodes, 50 edges, 8 communities, 3 hyperedges |
| Tool |
graphify semantic extraction — 4 parallel subagents |
Communities
| ID |
Name |
Nodes |
Cohesion |
| 0 |
Authentication & User Management |
6 |
0.72 |
| 1 |
Car Listings & Search |
5 |
0.68 |
| 2 |
Admin Panel |
4 |
0.80 |
| 3 |
Test Drive & Booking |
3 |
0.65 |
| 4 |
UI Components & Forms |
7 |
0.70 |
| 5 |
Database & Infrastructure |
11 |
0.85 |
| 6 |
Data Fetching & API Layer |
3 |
0.75 |
| 7 |
Home & Marketing |
4 |
0.60 |
Observations:
- Community 5 (Database & Infrastructure) is the largest and most cohesive (0.85). It anchors the graph — most other communities have at least one edge into it.
- Community 2 (Admin Panel) has the second-highest cohesion (0.80) and is tightly bounded, but its isolation is partly illusory: it depends on Community 5 via
is_admin() and getAdmin.
- Community 7 (Home & Marketing) is the least cohesive (0.60) and most peripheral. Home content management is loosely coupled to the rest of the system.
- Community 3 (Test Drive & Booking) is small and relatively isolated (0.65), communicating with the broader graph primarily through the
cars table and shared auth guards.
God Nodes
God nodes are those with the highest degree (most connections). They represent architectural chokepoints — high leverage, high risk.
1. createClient (Supabase) — degree 12
Every server action instantiates a Supabase client via this function. It is the sole gateway between application logic and the database. Any misconfiguration (e.g. using the anon key where the service-role key is required, or vice versa) propagates silently across all actions. Single point of failure for the entire data layer.
2. useFetch Hook — degree 8
Universal adapter between client-side React hooks and server actions. All data-fetching hooks (use-car-filters, use-car-admin, use-sign-in, etc.) funnel through this hook. This is a deliberate centralisation, but it means any change to useFetch has a blast radius covering all client data flows.
3. is_admin() SQL Function — degree 7
A SECURITY DEFINER PostgreSQL function that is the sole arbiter of admin access across 8 tables and at least one storage bucket. Both the application layer (getAdmin) and the database layer (RLS policies) call this function. See also: Hyperedge 2 and Surprising Connection 4.
4. Row Level Security Policies — degree 6
RLS policies govern all tables via is_admin() and auth.uid(). They are the last line of database defence. Their correctness depends entirely on the correctness of is_admin() — there is no independent fallback.
5. cars Table — degree 6
The central domain entity. Referenced by bookings, RLS policies, TypeScript enums, form writes, and all car query actions. Any schema change to cars ripples across communities 1, 2, 3, 4, and 5.
6. ensureProfile Action — degree 5
Acts as both an authentication guard and a silent user-record upsert on first sign-in. Two distinct responsibilities in one function. See also: Surprising Connection 5.
7. getAdmin Action — degree 5
The admin boundary in the application layer. Calls the database to verify role, then calls Next.js notFound() to reject unauthorised access. All admin pages depend on this action executing first.
8. carFormSchema (Zod) — degree 5
The shared contract between CarForm (UI), useAddCarForm (hook), and the createCar server action. Drift between the schema and either consumer is a silent validation gap.
Surprising Connections
Edges that cross community boundaries in unexpected ways, or reveal hidden coupling.
1. CarForm → cars Table (INFERRED, 0.80)
A UI component (Community 4) has a direct conceptual path to a database table (Community 5) with no explicit service layer between them. The form schema and the server action both reference the table structure directly. Tight coupling; a schema migration requires coordinated changes across UI, schema, and action.
2. Arcjet Security → signIn Action (INFERRED, 0.80)
Rate-limiting infrastructure is wired directly into the signIn server action rather than applied at a middleware or wrapper layer. This is the only server action with confirmed Arcjet integration, making the security posture inconsistent across the action surface. Cross-cutting concern without a cross-cutting enforcement point.
3. Header Component → UserRoleEnum (INFERRED, 0.85)
The header navigation component imports UserRoleEnum to conditionally render admin nav items. A database-mirrored enum — a domain/infrastructure concept — is being consumed directly by a presentation component. Business logic (role-gated navigation) is leaking into the presentation layer rather than being resolved upstream and passed as a prop.
4. is_admin() → RLS Policies (EXTRACTED, 1.0)
One SECURITY DEFINER function controls both the application-layer admin check (getAdmin) and the database-layer RLS policies. This violates defence in depth: a single exploit or misconfiguration in is_admin() simultaneously compromises both the app layer and the DB layer. The two layers are not independent.
5. ensureProfile → db_users_table (INFERRED, 0.90)
ensureProfile is framed as a routing/authentication guard, but it silently performs a DB upsert to create or update the user's profile record as a side effect. Hidden data persistence inside a function whose name suggests a read-only check. Callers may not be aware of the write.
6. CarStatusEnum → cars Table (INFERRED, 0.90)
The TypeScript CarStatusEnum manually mirrors the PostgreSQL car_status enum type. There is no code generation, no validation, and no test asserting their equivalence. A value added to the SQL enum will not appear in TypeScript (and vice versa) until a developer manually updates both — a silent divergence risk at runtime.
Hyperedges
Hyperedges capture multi-node patterns that form a coherent structural concern.
1. Authentication Guard Pattern
Nodes: ensureProfile, reservations_page, saved_cars_page, test_drive_page
All three protected pages invoke ensureProfile as their server-side auth guard before rendering. This is a consistent, centralised pattern: changing authentication or redirect behaviour for all protected routes requires a change in one place. The flip side is that ensureProfile's dual responsibility (guard + DB upsert) means a routing change could inadvertently affect data persistence.
2. Admin Role Security Chain
Nodes: is_admin(), RLS Policies, getAdmin, Admin Layout
A 4-node chain spanning SQL → application action → layout component. The chain provides layered access control, but each link calls the previous one, meaning the chain is only as strong as its weakest link: is_admin(). There is no independent verification at any layer.
3. TypeScript-to-SQL Enum Mirrors
Nodes: CarStatusEnum, UserRoleEnum, BookingStatusEnum, cars, users, test_drive_bookings
Six nodes participate in a manual mirroring pattern: three TypeScript enums each mirror a PostgreSQL enum type used in three tables. No code generation enforces consistency. A divergence in any pair will produce a runtime mismatch that TypeScript's type system cannot catch — the SQL type and the TS type are opaque to each other.
Suggested Questions
These questions are designed to trace the most structurally significant paths through the graph.
-
Admin escalation path — How does an unauthenticated user become an admin? Trace the full path from sign-up through role assignment to RLS enforcement.
-
is_admin() blast radius — If is_admin() were exploited, which tables and storage buckets would be compromised? What is the full blast radius across communities?
-
Enum drift impact — What happens to the UI when CarStatusEnum and the SQL car_status type diverge? Which components would silently break and how would the failure manifest?
-
Car listing end-to-end — How does a car listing flow from CarForm → createCar action → cars table → getCars → CarCard? Where are the validation boundaries?
-
Unprotected server actions — Which server actions have no Arcjet rate-limiting? Could they be abused without authentication, and what is the risk surface?
-
Test drive booking flow — How does the test drive booking flow work end-to-end: testDriveSchema → createTestDrive → DB row → Reservations page?
Audit Trail
Confidence Levels
All edges in this graph are assigned one of three confidence levels:
| Level |
Meaning |
EXTRACTED |
Directly observed in source — an import, a function call, an explicit SQL reference. Confidence ≥ 0.95. |
INFERRED |
Derived from semantic co-occurrence, naming patterns, or structural proximity. Confidence 0.70–0.94. |
AMBIGUOUS |
Possible connection, but insufficient evidence from the corpus. Confidence < 0.70. |
AMBIGUOUS edges in this run: All AMBIGUOUS edges were omitted. Signal strength was too low to include them without introducing misleading connections into the graph. The 50 edges present are exclusively EXTRACTED or INFERRED.
Extraction Method
Semantic analysis was performed by 4 parallel subagents, each responsible for a subset of the corpus. Node and edge candidates were merged and deduplicated in a final synthesis pass. Community detection used modularity-based clustering on the resulting adjacency structure.
Token Cost
| Phase |
Input Tokens |
Output Tokens |
| Extraction (4 subagents) |
~52,000 |
~18,000 |
| Total |
~52,000 |
~18,000 |
Note: This cost reflects a full cold extraction over the entire corpus. Incremental updates (--update) — re-analysing only changed files and merging deltas into the existing graph — would cost significantly less, typically 10–30% of a full run depending on the change surface.
GRAPH_REPORT — Car Dealership Knowledge Graph
Run Summary
Communities
Observations:
is_admin()andgetAdmin.carstable and shared auth guards.God Nodes
God nodes are those with the highest degree (most connections). They represent architectural chokepoints — high leverage, high risk.
1.
createClient (Supabase)— degree 12Every server action instantiates a Supabase client via this function. It is the sole gateway between application logic and the database. Any misconfiguration (e.g. using the anon key where the service-role key is required, or vice versa) propagates silently across all actions. Single point of failure for the entire data layer.
2.
useFetch Hook— degree 8Universal adapter between client-side React hooks and server actions. All data-fetching hooks (
use-car-filters,use-car-admin,use-sign-in, etc.) funnel through this hook. This is a deliberate centralisation, but it means any change touseFetchhas a blast radius covering all client data flows.3.
is_admin() SQL Function— degree 7A
SECURITY DEFINERPostgreSQL function that is the sole arbiter of admin access across 8 tables and at least one storage bucket. Both the application layer (getAdmin) and the database layer (RLS policies) call this function. See also: Hyperedge 2 and Surprising Connection 4.4.
Row Level Security Policies— degree 6RLS policies govern all tables via
is_admin()andauth.uid(). They are the last line of database defence. Their correctness depends entirely on the correctness ofis_admin()— there is no independent fallback.5.
cars Table— degree 6The central domain entity. Referenced by bookings, RLS policies, TypeScript enums, form writes, and all car query actions. Any schema change to
carsripples across communities 1, 2, 3, 4, and 5.6.
ensureProfile Action— degree 5Acts as both an authentication guard and a silent user-record upsert on first sign-in. Two distinct responsibilities in one function. See also: Surprising Connection 5.
7.
getAdmin Action— degree 5The admin boundary in the application layer. Calls the database to verify role, then calls Next.js
notFound()to reject unauthorised access. All admin pages depend on this action executing first.8.
carFormSchema (Zod)— degree 5The shared contract between
CarForm(UI),useAddCarForm(hook), and thecreateCarserver action. Drift between the schema and either consumer is a silent validation gap.Surprising Connections
Edges that cross community boundaries in unexpected ways, or reveal hidden coupling.
1.
CarForm → cars Table(INFERRED, 0.80)A UI component (Community 4) has a direct conceptual path to a database table (Community 5) with no explicit service layer between them. The form schema and the server action both reference the table structure directly. Tight coupling; a schema migration requires coordinated changes across UI, schema, and action.
2.
Arcjet Security → signIn Action(INFERRED, 0.80)Rate-limiting infrastructure is wired directly into the
signInserver action rather than applied at a middleware or wrapper layer. This is the only server action with confirmed Arcjet integration, making the security posture inconsistent across the action surface. Cross-cutting concern without a cross-cutting enforcement point.3.
Header Component → UserRoleEnum(INFERRED, 0.85)The header navigation component imports
UserRoleEnumto conditionally render admin nav items. A database-mirrored enum — a domain/infrastructure concept — is being consumed directly by a presentation component. Business logic (role-gated navigation) is leaking into the presentation layer rather than being resolved upstream and passed as a prop.4.
is_admin() → RLS Policies(EXTRACTED, 1.0)One
SECURITY DEFINERfunction controls both the application-layer admin check (getAdmin) and the database-layer RLS policies. This violates defence in depth: a single exploit or misconfiguration inis_admin()simultaneously compromises both the app layer and the DB layer. The two layers are not independent.5.
ensureProfile → db_users_table(INFERRED, 0.90)ensureProfileis framed as a routing/authentication guard, but it silently performs a DB upsert to create or update the user's profile record as a side effect. Hidden data persistence inside a function whose name suggests a read-only check. Callers may not be aware of the write.6.
CarStatusEnum → cars Table(INFERRED, 0.90)The TypeScript
CarStatusEnummanually mirrors the PostgreSQLcar_statusenum type. There is no code generation, no validation, and no test asserting their equivalence. A value added to the SQL enum will not appear in TypeScript (and vice versa) until a developer manually updates both — a silent divergence risk at runtime.Hyperedges
Hyperedges capture multi-node patterns that form a coherent structural concern.
1. Authentication Guard Pattern
Nodes:
ensureProfile,reservations_page,saved_cars_page,test_drive_pageAll three protected pages invoke
ensureProfileas their server-side auth guard before rendering. This is a consistent, centralised pattern: changing authentication or redirect behaviour for all protected routes requires a change in one place. The flip side is thatensureProfile's dual responsibility (guard + DB upsert) means a routing change could inadvertently affect data persistence.2. Admin Role Security Chain
Nodes:
is_admin(),RLS Policies,getAdmin,Admin LayoutA 4-node chain spanning SQL → application action → layout component. The chain provides layered access control, but each link calls the previous one, meaning the chain is only as strong as its weakest link:
is_admin(). There is no independent verification at any layer.3. TypeScript-to-SQL Enum Mirrors
Nodes:
CarStatusEnum,UserRoleEnum,BookingStatusEnum,cars,users,test_drive_bookingsSix nodes participate in a manual mirroring pattern: three TypeScript enums each mirror a PostgreSQL enum type used in three tables. No code generation enforces consistency. A divergence in any pair will produce a runtime mismatch that TypeScript's type system cannot catch — the SQL type and the TS type are opaque to each other.
Suggested Questions
These questions are designed to trace the most structurally significant paths through the graph.
Admin escalation path — How does an unauthenticated user become an admin? Trace the full path from sign-up through role assignment to RLS enforcement.
is_admin()blast radius — Ifis_admin()were exploited, which tables and storage buckets would be compromised? What is the full blast radius across communities?Enum drift impact — What happens to the UI when
CarStatusEnumand the SQLcar_statustype diverge? Which components would silently break and how would the failure manifest?Car listing end-to-end — How does a car listing flow from
CarForm→createCaraction →carstable →getCars→CarCard? Where are the validation boundaries?Unprotected server actions — Which server actions have no Arcjet rate-limiting? Could they be abused without authentication, and what is the risk surface?
Test drive booking flow — How does the test drive booking flow work end-to-end:
testDriveSchema→createTestDrive→ DB row → Reservations page?Audit Trail
Confidence Levels
All edges in this graph are assigned one of three confidence levels:
EXTRACTEDINFERREDAMBIGUOUSAMBIGUOUS edges in this run: All AMBIGUOUS edges were omitted. Signal strength was too low to include them without introducing misleading connections into the graph. The 50 edges present are exclusively
EXTRACTEDorINFERRED.Extraction Method
Semantic analysis was performed by 4 parallel subagents, each responsible for a subset of the corpus. Node and edge candidates were merged and deduplicated in a final synthesis pass. Community detection used modularity-based clustering on the resulting adjacency structure.
Token Cost
Note: This cost reflects a full cold extraction over the entire corpus. Incremental updates (
--update) — re-analysing only changed files and merging deltas into the existing graph — would cost significantly less, typically 10–30% of a full run depending on the change surface.