docs: add architecture reports, public-landing routing plan, build-a-page tutorial, self-serve signup phase-2 design
All checks were successful
Mirror to GitHub / mirror (push) Successful in 5s
CI / frontend (pull_request) Successful in 6m45s
CI / e2e (pull_request) Successful in 10m13s
CI / backend (pull_request) Successful in 11m27s

- docs/architecture/: god-node map + report (2026-05-06), workflows.json/html + analysis snapshot
- docs/plans/2026-05-13-public-landing-routing-refactor.md
- docs/tutorials/build-a-page.md
- abc-feat-self-serve-signup-phase-2-design-20260507-112020.md (root)

Core dumps (core.144926, core.145678, docs/architecture/core.1392564) and
agent .remember/ state are intentionally left untracked.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-13 23:59:29 -04:00
parent dc88797469
commit e5b26245ca
8 changed files with 7132 additions and 0 deletions

View File

@@ -0,0 +1,458 @@
---
title: God Node Architecture Report
date: 2026-05-06
tags:
- architecture
- dependency-graph
- god-nodes
---
# God Node Architecture Report — 2026-05-06
## Summary
This is a static dependency and churn report for `backend/app` and `frontend/src`.
The main finding: ResolutionFlow has several expected infrastructure hubs, plus a smaller set of behavioral hubs that deserve care when touched. The highest-risk candidates are not the most-imported files; they are the files that combine high size, high churn, and many outbound dependencies.
Highest-risk behavioral hubs:
1. `frontend/src/pages/AssistantChatPage.tsx`
2. `frontend/src/pages/TreeNavigationPage.tsx`
3. `frontend/src/pages/ProceduralNavigationPage.tsx`
4. `backend/app/services/flowpilot_engine.py`
5. `backend/app/api/endpoints/ai_sessions.py`
6. `backend/app/api/endpoints/sessions.py`
7. `backend/app/api/endpoints/trees.py`
8. `backend/app/api/endpoints/admin.py`
Expected infrastructure hubs:
- `frontend/src/lib/utils.ts`
- `frontend/src/types/index.ts`
- `frontend/src/api/index.ts`
- `frontend/src/api/client.ts`
- `frontend/src/lib/toast.ts`
- `backend/app/core/database.py`
- `backend/app/api/deps.py`
- `backend/app/core/config.py`
- SQLAlchemy models such as `User`, `Tree`, `AISession`, and `Account`
Do not treat all high-degree nodes as bad. A utility, type barrel, API barrel, router, or ORM model can be central by design. The suspicious shape is: high outbound dependencies + high churn + large file + multiple unrelated reasons to change.
## Method
Inputs:
- Source files: `backend/app/**/*.py`, `frontend/src/**/*.ts`, `frontend/src/**/*.tsx`
- Excluded: tests, docs, migrations, build output, env files
- Static imports:
- Python: regex import extraction for `import ...` and `from ... import ...`
- TypeScript/TSX: static `import/export from` plus dynamic `import(...)`
- Churn: `git log --name-only --since='90 days ago'`
- Size: line count
Scoring used for triage, not truth:
```text
score = inbound_edges * 2
+ outbound_edges * 1.5
+ min(churn_90d, 30) * 1.2
+ min(lines_of_code / 100, 20)
```
Caveats:
- `backend/app/__init__.py` appears as a very high inbound node because static imports through `app.*` resolve through the package root in this simple parser. Ignore it as a parser artifact.
- Barrel files (`frontend/src/api/index.ts`, `frontend/src/types/index.ts`) intentionally create cycles with the modules they export. This is a known TypeScript graph artifact, not automatically a design flaw.
- Static graphs do not show runtime call volume. This report answers “where is the code structurally central?” not “what is hot in production?”
## Visual Map
Primary visualization:
- Open `docs/architecture/god-node-map-2026-05-06.canvas` in Obsidian.
- This uses Obsidian Canvas, so no community plugin is required.
- The Canvas groups nodes by interpretation instead of drawing every import edge.
The dense dependency graph is intentionally not the default view anymore. For architecture review, the useful split is:
1. Which nodes are high-risk behavioral hubs?
2. Which central nodes are expected infrastructure?
3. What should self-serve signup avoid touching?
### Risk Overview
```mermaid
flowchart LR
Work["Self-serve signup work"] --> Boundaries["Keep changes at boundaries"]
Boundaries --> BillingStore["useBillingStore"]
Boundaries --> Guards["router/dependency guards"]
Boundaries --> BillingService["BillingService"]
Assistant["AssistantChatPage.tsx\nfrontend god node"] -. avoid unrelated edits .-> Work
FlowPilot["flowpilot_engine.py\nbackend god node"] -. avoid unrelated edits .-> Work
AISessions["ai_sessions.py\ncontroller + mapper"] -. do not add billing logic .-> Work
SessionsTrees["sessions.py / trees.py\nlarge endpoint hubs"] -. mount guards, avoid handler sprawl .-> Work
Utils["utils / toast / api client / database\nexpected infrastructure"] -. do not refactor just because central .-> Work
```
### Frontend Hotspots
```mermaid
flowchart TB
Router["router.tsx\nroute hub"] --> Assistant["AssistantChatPage.tsx\nhighest risk"]
Router --> TreeNav["TreeNavigationPage.tsx"]
Router --> ProcNav["ProceduralNavigationPage.tsx"]
Router --> TreeLibrary["TreeLibraryPage.tsx"]
Router --> TreeEditor["TreeEditorPage.tsx"]
Router --> SessionDetail["SessionDetailPage.tsx"]
Assistant --> ExtractA["Extract one workflow at a time"]
TreeNav --> ExtractB["Extract orchestration hooks when touched"]
ProcNav --> ExtractB
Infra["utils.ts / toast.ts / api/client.ts / types/index.ts"]
Assistant --> Infra
TreeNav --> Infra
ProcNav --> Infra
```
### Backend Hotspots
```mermaid
flowchart TB
Deps["api/deps.py\nboundary hub"] --> DB["database + models\nexpected infrastructure"]
AISessions["api/endpoints/ai_sessions.py"] --> FlowPilot["services/flowpilot_engine.py"]
Sessions["api/endpoints/sessions.py"] --> Export["services/export_service.py"]
Trees["api/endpoints/trees.py"] --> DB
Admin["api/endpoints/admin.py"] --> DB
SelfServe["Self-serve backend"] --> Deps
SelfServe --> Billing["BillingService + subscriptions"]
SelfServe -. avoid .-> AISessions
SelfServe -. avoid .-> Sessions
SelfServe -. avoid .-> Trees
SelfServe -. avoid .-> FlowPilot
```
## Obsidian Visualization Options
Best default: use the generated Canvas file. Obsidian Canvas is a core plugin and stores diagrams as `.canvas` files, so it works without adding community plugin risk.
Optional plugins worth considering:
- Excalidraw: best if you want hand-edited architecture diagrams that feel like a whiteboard.
- Markmind: useful if you want this report as a mind map or outline-first view.
- Diagrams.net / draw.io plugin: useful for formal boxes-and-arrows diagrams, but heavier than Canvas for this use case.
Recommendation: start with Canvas. Add Excalidraw only if you want to manually sketch over the architecture map during planning sessions.
## Top Centrality Candidates
| Rank | File | In | Out | 90d churn | LOC | Classification | Read |
|---:|---|---:|---:|---:|---:|---|---|
| 1 | `frontend/src/lib/utils.ts` | 225 | 0 | 1 | 32 | Infrastructure hub | Good |
| 2 | `frontend/src/types/index.ts` | 137 | 32 | 22 | 103 | Barrel hub | Watch |
| 3 | `backend/app/core/database.py` | 110 | 2 | 2 | 47 | Infrastructure hub | Good |
| 4 | `backend/app/models/user.py` | 90 | 7 | 13 | 130 | Domain model hub | Watch |
| 5 | `frontend/src/api/index.ts` | 38 | 40 | 26 | 41 | API barrel hub | Watch |
| 6 | `frontend/src/lib/toast.ts` | 79 | 0 | 1 | 72 | Infrastructure hub | Good |
| 7 | `frontend/src/router.tsx` | 1 | 72 | 48 | 308 | Router hub | Watch |
| 8 | `backend/app/api/deps.py` | 56 | 9 | 13 | 292 | Auth/dependency hub | Watch |
| 9 | `backend/app/core/config.py` | 44 | 1 | 27 | 232 | Config hub | Good, but churny |
| 10 | `frontend/src/pages/AssistantChatPage.tsx` | 2 | 39 | 77 | 2493 | Behavioral hub | High risk |
| 11 | `backend/app/models/tree.py` | 43 | 10 | 11 | 233 | Domain model hub | Watch |
| 12 | `frontend/src/api/client.ts` | 51 | 2 | 5 | 173 | API client hub | Good |
| 13 | `frontend/src/pages/TreeNavigationPage.tsx` | 2 | 31 | 33 | 1385 | Behavioral hub | High risk |
| 14 | `frontend/src/components/ui/Button.tsx` | 43 | 2 | 6 | 65 | UI primitive | Good |
| 15 | `backend/app/models/ai_session.py` | 32 | 11 | 11 | 314 | Domain model hub | Watch |
| 16 | `frontend/src/pages/ProceduralNavigationPage.tsx` | 1 | 33 | 22 | 1021 | Behavioral hub | High risk |
| 17 | `frontend/src/pages/TreeLibraryPage.tsx` | 3 | 27 | 38 | 546 | Behavioral hub | Medium risk |
| 18 | `backend/app/models/account.py` | 29 | 11 | 8 | 70 | Domain model hub | Watch |
| 19 | `backend/app/api/endpoints/sessions.py` | 0 | 24 | 26 | 1186 | Endpoint hub | High risk |
| 20 | `frontend/src/pages/TreeEditorPage.tsx` | 2 | 20 | 28 | 928 | Behavioral hub | Medium risk |
| 21 | `frontend/src/pages/SessionDetailPage.tsx` | 2 | 21 | 28 | 623 | Behavioral hub | Medium risk |
| 22 | `backend/app/api/endpoints/trees.py` | 0 | 20 | 23 | 1332 | Endpoint hub | High risk |
| 23 | `backend/app/api/endpoints/ai_sessions.py` | 0 | 15 | 32 | 1173 | Endpoint hub | High risk |
| 24 | `backend/app/services/flowpilot_engine.py` | 1 | 17 | 20 | 1793 | Behavioral service hub | High risk |
## Findings
### 1. `AssistantChatPage.tsx` Is The Clearest Frontend God Node
Evidence:
- 2,493 LOC
- 39 outbound dependencies
- 77 changes in 90 days
- Owns routing, chat selection, magic-moment pickup state, task-lane state, upload state, facts, suggested fixes, preview state, script-builder surfaces, modals, keyboard shortcuts, local/session storage, and message rendering orchestration.
Classification: behavioral god node.
This file has too many reasons to change. It is not dangerous because many files import it; it is dangerous because it imports many things, owns many workflows, and changes constantly.
Recommended response:
- Do not do a broad refactor in isolation.
- When touching it, extract one workflow at a time behind a hook or controller:
- `useTaskLaneState`
- `usePilotPickup`
- `useSuggestedFixPreview`
- `useSessionFacts`
- `useScriptBuilderPanelState`
- Keep the page as an orchestrator, but move state machines and async effects out.
- Before major changes, add narrow regression tests around task-lane ownership and session switching.
Priority: high, opportunistic refactor.
### 2. `flowpilot_engine.py` Is A Real Backend Behavioral Hub
Evidence:
- 1,793 LOC
- 17 outbound dependencies
- 20 changes in 90 days
- Owns prompts, structured output parsing, session start, step generation, confidence, close/resolve/escalate behaviors, and likely several persistence transitions.
Classification: behavioral service hub.
This is not surprising: FlowPilot is core product logic. The risk is that prompt text, model call orchestration, persistence, and business rules live close together.
Recommended response:
- Keep this file stable during unrelated work.
- Extract only when a change naturally creates a seam:
- prompt construction
- structured output validation
- session state transition persistence
- documentation/status update generation
- Avoid routing new self-serve billing or account logic through this service.
Priority: high, but avoid speculative refactor.
### 3. AI Session Endpoint Is Acting As A Controller Plus Mapper
File: `backend/app/api/endpoints/ai_sessions.py`
Evidence:
- 1,173 LOC
- 15 outbound dependencies
- 32 changes in 90 days
- Contains endpoint handlers, quota checks, response mapping, ownership behavior, chat wiring, and PSA retry integration.
Classification: endpoint god node.
The endpoint does more than route HTTP to services. Some helper logic is fine, but the mapper and ownership rules should stay stable and test-backed.
Recommended response:
- Keep endpoint handlers thin when adding new features.
- Move reusable mapping logic such as `_build_session_detail` to a schema/service helper if it is touched again.
- Do not add subscription or onboarding behavior directly here; mount dependencies at router level where possible.
Priority: high for change discipline, medium for refactor.
### 4. Classic Session And Tree Endpoints Are Large, But Mostly Expected
Files:
- `backend/app/api/endpoints/sessions.py`
- `backend/app/api/endpoints/trees.py`
Evidence:
- `sessions.py`: 1,186 LOC, 24 outbound dependencies, 26 changes
- `trees.py`: 1,332 LOC, 20 outbound dependencies, 23 changes
Classification: endpoint hubs.
These files are not surprising in a CRUD-heavy FastAPI app, but they are large enough that behavioral additions should be routed through services or focused helpers.
Recommended response:
- For new subscription guards, mount dependencies instead of inserting repeated checks inside handlers.
- For new tree/session behavior, prefer service functions over adding more endpoint-local logic.
- Add regression tests before modifying export, sharing, ownership, or limit-check paths.
Priority: medium-high.
### 5. Frontend Page-Level Hubs Are The Main UI Risk
Files:
- `frontend/src/pages/TreeNavigationPage.tsx`
- `frontend/src/pages/ProceduralNavigationPage.tsx`
- `frontend/src/pages/TreeLibraryPage.tsx`
- `frontend/src/pages/TreeEditorPage.tsx`
- `frontend/src/pages/SessionDetailPage.tsx`
Pattern:
- High outbound dependencies
- Meaningful churn
- Page components own orchestration plus rendering
Recommended response:
- Treat page components as shells where possible.
- Extract stable workflow hooks before adding another workflow.
- Keep design updates scoped to subcomponents.
- Avoid adding global state unless the state truly spans routes.
Priority: medium, with `TreeNavigationPage.tsx` and `ProceduralNavigationPage.tsx` highest.
### 6. Auth Store Is Central But Not Yet A Problem
File: `frontend/src/store/authStore.ts`
Evidence:
- 21 inbound dependencies
- 5 outbound dependencies
- 144 LOC
- 6 changes in 90 days
Classification: central state hub.
This is a normal app hub. It becomes risky if billing, onboarding, feature gates, and auth all accumulate here. The self-serve specs choice to create `useBillingStore` instead of embedding billing state in `/auth/me` is the right architectural direction.
Recommended response:
- Keep auth store focused on identity/session/account bootstrap.
- Put billing in `useBillingStore`.
- Put onboarding wizard state in a narrow API/hook, not in auth.
Priority: watch.
### 7. Barrels Are Creating A Large Frontend Cycle
Cycle:
- 42 files under `frontend/src/api/*`
- Driven by `frontend/src/api/index.ts` exporting modules while some modules import from the barrel or share `apiClient`.
Classification: barrel cycle / tooling artifact with some real coupling risk.
This is common and not urgent. It can confuse static tools and make imports less explicit.
Recommended response:
- Prefer direct imports from concrete API modules in new code:
- Good: `import { aiSessionsApi } from '@/api/aiSessions'`
- Avoid: `import { aiSessionsApi } from '@/api'`
- Keep `api/index.ts` only for broad convenience if it remains useful.
- Do not spend time untangling old imports unless dependency tooling starts enforcing boundaries.
Priority: low.
### 8. Backend ORM Model Cycles Are Expected
Cycle:
- 17 files across account/user/tree/session/subscription/category/share models
- 5 files across AI session branch/handoff/step models
Classification: SQLAlchemy relationship cycle.
This is expected in an ORM with bidirectional relationships. It does not mean the model layer is broken.
Recommended response:
- Keep imports guarded with `TYPE_CHECKING` where possible.
- Keep model methods thin.
- Put behavior in services, not model properties beyond simple derived flags.
Priority: low.
## Ranked Action List
### Do Now
No immediate large refactor is recommended before self-serve signup work. The report does not show a blocker.
### Do During Self-Serve Work
1. Keep `useBillingStore` separate from `authStore`.
2. Mount subscription and email verification guards at router/dependency boundaries, not inside individual endpoint handlers.
3. Keep new billing service behavior out of existing `ai_sessions.py`, `sessions.py`, and `trees.py` except for dependency wiring.
4. Prefer direct frontend API imports over `@/api` barrel imports in new code.
### Do Opportunistically
1. Extract one workflow at a time from `AssistantChatPage.tsx`.
2. Extract prompt construction or structured response validation from `flowpilot_engine.py` when touched.
3. Move response mapping helpers out of `ai_sessions.py` if those helpers change again.
4. Split page-level orchestration hooks out of `TreeNavigationPage.tsx` and `ProceduralNavigationPage.tsx` as features touch them.
### Avoid
1. Do not split `utils.ts`, `toast.ts`, `api/client.ts`, or `core/database.py` just because they are central.
2. Do not refactor ORM model cycles unless they cause import/runtime issues.
3. Do not start a broad barrel-file cleanup unless tooling or build performance requires it.
## Raw Metrics Snapshot
Total analyzed files: 783
Total static import edges: 2,946
Top inbound hubs:
| File | Inbound | Outbound | 90d churn | LOC | Note |
|---|---:|---:|---:|---:|---|
| `frontend/src/lib/utils.ts` | 225 | 0 | 1 | 32 | Healthy utility hub |
| `frontend/src/types/index.ts` | 137 | 32 | 22 | 103 | Barrel hub |
| `backend/app/core/database.py` | 110 | 2 | 2 | 47 | Healthy infrastructure hub |
| `backend/app/models/user.py` | 90 | 7 | 13 | 130 | Domain model hub |
| `frontend/src/lib/toast.ts` | 79 | 0 | 1 | 72 | Healthy utility hub |
| `backend/app/api/deps.py` | 56 | 9 | 13 | 292 | Auth/dependency hub |
| `frontend/src/api/client.ts` | 51 | 2 | 5 | 173 | API infrastructure hub |
| `backend/app/core/config.py` | 44 | 1 | 27 | 232 | Config hub, high churn |
| `backend/app/models/tree.py` | 43 | 10 | 11 | 233 | Domain model hub |
| `frontend/src/components/ui/Button.tsx` | 43 | 2 | 6 | 65 | UI primitive |
Top outbound hubs:
| File | Inbound | Outbound | 90d churn | LOC | Note |
|---|---:|---:|---:|---:|---|
| `frontend/src/router.tsx` | 1 | 72 | 48 | 308 | Router hub, acceptable |
| `frontend/src/api/index.ts` | 38 | 40 | 26 | 41 | Barrel hub |
| `frontend/src/pages/AssistantChatPage.tsx` | 2 | 39 | 77 | 2493 | High-risk behavioral hub |
| `frontend/src/pages/ProceduralNavigationPage.tsx` | 1 | 33 | 22 | 1021 | High-risk behavioral hub |
| `frontend/src/pages/TreeNavigationPage.tsx` | 2 | 31 | 33 | 1385 | High-risk behavioral hub |
| `frontend/src/pages/TreeLibraryPage.tsx` | 3 | 27 | 38 | 546 | Medium-risk page hub |
| `backend/app/api/endpoints/sessions.py` | 0 | 24 | 26 | 1186 | High-risk endpoint hub |
| `backend/app/api/endpoints/admin.py` | 0 | 22 | 10 | 1430 | Admin endpoint hub |
| `frontend/src/pages/SessionDetailPage.tsx` | 2 | 21 | 28 | 623 | Medium-risk page hub |
| `backend/app/api/endpoints/auth.py` | 0 | 20 | 9 | 721 | Auth endpoint hub |
| `backend/app/api/endpoints/trees.py` | 0 | 20 | 23 | 1332 | High-risk endpoint hub |
| `frontend/src/pages/ProceduralEditorPage.tsx` | 1 | 20 | 16 | 475 | Medium-risk page hub |
| `frontend/src/pages/TreeEditorPage.tsx` | 2 | 20 | 28 | 928 | Medium-risk page hub |
Detected cycles:
| Size | Area | Interpretation |
|---:|---|---|
| 42 | `frontend/src/api/*` | Barrel/export cycle. Low urgency. |
| 17 | backend ORM models | Expected SQLAlchemy relationship cycle. Low urgency. |
| 5 | backend AI session models | Expected relationship cycle. Low urgency. |
| 2 | tree preview components | Small component cycle; inspect only if these files become troublesome. |
## How To Re-run
The current environment does not have native Python, so this report was generated with Node-based static parsing plus shell/git commands. A future repeat can use a dedicated script if this becomes a regular architecture check.
Suggested future command shape:
```bash
node scripts/architecture/god-node-report.mjs
```
If this becomes a recurring check, add:
- `scripts/architecture/god-node-report.mjs`
- `docs/architecture/god-node-report-YYYY-MM-DD.md`
- optional `docs/architecture/god-node-graph-YYYY-MM-DD.mmd`