# novanhleonard-sys/pln architecture

> Architecture diagram of the GitHub repository novanhleonard-sys/pln, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-10-03). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/novanhleonard-sys/pln
- Repository: https://github.com/novanhleonard-sys/pln

## Overview

Peta LN is a folklore-story platform for discovering stories on a map, reading or listening to them, and submitting contributions; staff manage content and its AI-assisted processing. The web app routes users into discovery, reading, contribution, profile, and administration features. A worker polls Supabase jobs and dispatches registered processing stages through an AI provider registry. The graph preserves documented stages and major features, but source excerpts are incomplete and the README is empty; unverified runtime links are omitted.

Main entry points: [`apps/web/src/main.tsx`](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/main.tsx) (Web routes), [`apps/web/src/features/admin/AdminCenter.tsx`](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminCenter.tsx) (Admin workspace), [`apps/web/src/features/reader/baca/Baca.tsx`](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/reader/baca/Baca.tsx) (Story reader), [`apps/web/src/features/contribute/ContributeForm.tsx`](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/contribute/ContributeForm.tsx) (Contribution form)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_web["Story experience"]
  node_app["Web routes<br/>[main.tsx]"]
  node_discovery["Map discovery"]
  node_search["Story search<br/>[Search.tsx]"]
  node_storycard["Story cards<br/>[StoryCard.tsx]"]
  node_reader["Story reader<br/>[Baca.tsx]"]
  node_readerprefs["Reader preferences<br/>[useReaderStore.ts]"]
  node_adaptui["Adaptation experience"]
  node_dongeng["Story audio mode<br/>[DongengMode.tsx]"]
  node_profile["Reader profile"]
end

subgraph group_contrib["Community contributions"]
  node_contributeform["Contribution form<br/>[ContributeForm.tsx]"]
  node_similar["Story matching"]
  node_contribstatus["Contribution tracking"]
end

subgraph group_admin["Content administration"]
  node_admincenter["Admin workspace<br/>[AdminCenter.tsx]"]
  node_admindash["Admin dashboard<br/>[AdminDashboard.tsx]"]
  node_adminedit["Content editing"]
  node_aistyle["AI style controls<br/>[AdminGayaAI.tsx]"]
  node_regions["Region groups"]
  node_voices["Voice library"]
end

subgraph group_worker["AI processing"]
  node_worker["Job worker<br/>[runner.ts]"]
  node_stages["Processing stages"]
  node_registry["AI provider registry<br/>[registry.ts]"]
  node_gemini["Gemini provider<br/>[gemini.ts]"]
  node_budget["AI budget guard<br/>[budget.ts]"]
  node_tierjob["Tier calculation<br/>[calculate.ts]"]
end

subgraph group_platform["Shared platform"]
  node_auth["Authentication state<br/>[AuthStore.ts]"]
  node_webclient["Web data client<br/>[supabase.ts]"]
  node_database[("Supabase data")]
  node_readtracking["Reading analytics"]
  node_adaptfunction["Adaptation requests<br/>[index.ts]"]
  node_contribfunction["Contribution submission<br/>[index.ts]"]
end

node_visitor(("Reader / contributor"))

node_visitor -->|"opens"| node_app
node_app -->|"routes to"| node_discovery
node_app -->|"routes to"| node_reader
node_app -->|"routes to"| node_contributeform
node_app -->|"routes to"| node_profile
node_app -->|"routes to"| node_admincenter
node_app -->|"initializes"| node_auth
node_discovery -->|"queries stories"| node_database
node_readerprefs -->|"syncs preferences"| node_database
node_readerprefs -->|"loads preferences"| node_database
node_reader -.->|"tracks reading"| node_readtracking
node_readtracking -->|"upserts sessions"| node_database
node_reader -.->|"uses preferences"| node_readerprefs
node_reader -.->|"offers adaptation"| node_adaptui
node_reader -.->|"offers audio mode"| node_dongeng
node_contributeform -->|"checks matches"| node_similar
node_contributeform -.->|"submits contribution"| node_database
node_contributeform -.->|"requests submission"| node_contribfunction
node_contribstatus -.->|"reads submissions"| node_database
node_admincenter -->|"renders"| node_admindash
node_admincenter -->|"renders"| node_adminedit
node_admincenter -->|"renders"| node_aistyle
node_admincenter -->|"renders"| node_regions
node_admincenter -->|"renders"| node_voices
node_adminedit -.->|"manages content"| node_database
node_worker -->|"dispatches jobs"| node_stages
node_worker -->|"runs tier check"| node_tierjob
node_stages -->|"requests generation"| node_registry
node_registry -->|"checks budget"| node_budget
node_registry -.->|"dispatches generation"| node_gemini
node_worker -->|"polls jobs"| node_database
node_stages -->|"reads and writes records"| node_database
node_adaptui -.->|"requests adaptation"| node_adaptfunction
node_auth -->|"authenticates through"| node_webclient
node_webclient -->|"connects to"| node_database

click node_app "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/main.tsx"
click node_discovery "https://github.com/novanhleonard-sys/pln/tree/main/apps/web/src/features/map"
click node_search "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/search/Search.tsx"
click node_storycard "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/story-card/StoryCard.tsx"
click node_reader "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/reader/baca/Baca.tsx"
click node_readerprefs "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/reader/store/useReaderStore.ts"
click node_adaptui "https://github.com/novanhleonard-sys/pln/tree/main/apps/web/src/features/reader/adapt"
click node_dongeng "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/reader/dongeng/DongengMode.tsx"
click node_profile "https://github.com/novanhleonard-sys/pln/tree/main/apps/web/src/features/profile"
click node_contributeform "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/contribute/ContributeForm.tsx"
click node_similar "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/contribute/SimilarStoriesCheck.tsx"
click node_contribstatus "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/contribute/MyContributions.tsx"
click node_admincenter "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminCenter.tsx"
click node_admindash "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminDashboard.tsx"
click node_adminedit "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminEditKonten.tsx"
click node_aistyle "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminGayaAI.tsx"
click node_regions "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminKelompokDaerah.tsx"
click node_voices "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminPustakaSuara.tsx"
click node_worker "https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/core/runner.ts"
click node_stages "https://github.com/novanhleonard-sys/pln/tree/main/apps/worker/src/stages"
click node_registry "https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/providers/registry.ts"
click node_gemini "https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/providers/gemini.ts"
click node_budget "https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/core/budget.ts"
click node_tierjob "https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/jobs/tier/calculate.ts"
click node_auth "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/auth/AuthStore.ts"
click node_webclient "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/lib/supabase.ts"
click node_readtracking "https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/analytics/useReadSessionTracker.ts"
click node_adaptfunction "https://github.com/novanhleonard-sys/pln/blob/main/supabase/functions/request_adaptation/index.ts"
click node_contribfunction "https://github.com/novanhleonard-sys/pln/blob/main/supabase/functions/submit_contribution/index.ts"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_app,node_discovery,node_search,node_storycard,node_reader,node_readerprefs,node_adaptui,node_dongeng,node_profile toneBlue
class node_contributeform,node_similar,node_contribstatus toneAmber
class node_admincenter,node_admindash,node_adminedit,node_aistyle,node_regions,node_voices toneMint
class node_worker,node_stages,node_registry,node_gemini,node_budget,node_tierjob toneRose
class node_auth,node_webclient,node_database,node_readtracking,node_adaptfunction,node_contribfunction,node_visitor toneIndigo
```

## Components

### Story experience

- [Web routes](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/main.tsx): `apps/web/src/main.tsx`
- [Map discovery](https://github.com/novanhleonard-sys/pln/tree/main/apps/web/src/features/map): `apps/web/src/features/map`
- [Story search](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/search/Search.tsx): `apps/web/src/features/search/Search.tsx`
- [Story cards](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/story-card/StoryCard.tsx): `apps/web/src/features/story-card/StoryCard.tsx`
- [Story reader](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/reader/baca/Baca.tsx): `apps/web/src/features/reader/baca/Baca.tsx`
- [Reader preferences](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/reader/store/useReaderStore.ts): `apps/web/src/features/reader/store/useReaderStore.ts`
- [Adaptation experience](https://github.com/novanhleonard-sys/pln/tree/main/apps/web/src/features/reader/adapt): `apps/web/src/features/reader/adapt`
- [Story audio mode](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/reader/dongeng/DongengMode.tsx): `apps/web/src/features/reader/dongeng/DongengMode.tsx`
- [Reader profile](https://github.com/novanhleonard-sys/pln/tree/main/apps/web/src/features/profile): `apps/web/src/features/profile`

### Community contributions

- [Contribution form](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/contribute/ContributeForm.tsx): `apps/web/src/features/contribute/ContributeForm.tsx`
- [Story matching](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/contribute/SimilarStoriesCheck.tsx): `apps/web/src/features/contribute/SimilarStoriesCheck.tsx`
- [Contribution tracking](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/contribute/MyContributions.tsx): `apps/web/src/features/contribute/MyContributions.tsx`

### Content administration

- [Admin workspace](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminCenter.tsx): `apps/web/src/features/admin/AdminCenter.tsx`
- [Admin dashboard](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminDashboard.tsx): `apps/web/src/features/admin/AdminDashboard.tsx`
- [Content editing](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminEditKonten.tsx): `apps/web/src/features/admin/AdminEditKonten.tsx`
- [AI style controls](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminGayaAI.tsx): `apps/web/src/features/admin/AdminGayaAI.tsx`
- [Region groups](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminKelompokDaerah.tsx): `apps/web/src/features/admin/AdminKelompokDaerah.tsx`
- [Voice library](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/admin/AdminPustakaSuara.tsx): `apps/web/src/features/admin/AdminPustakaSuara.tsx`

### AI processing

- [Job worker](https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/core/runner.ts): `apps/worker/src/core/runner.ts`
- [Processing stages](https://github.com/novanhleonard-sys/pln/tree/main/apps/worker/src/stages): `apps/worker/src/stages`
- [AI provider registry](https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/providers/registry.ts): `apps/worker/src/providers/registry.ts`
- [Gemini provider](https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/providers/gemini.ts): `apps/worker/src/providers/gemini.ts`
- [AI budget guard](https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/core/budget.ts): `apps/worker/src/core/budget.ts`
- [Tier calculation](https://github.com/novanhleonard-sys/pln/blob/main/apps/worker/src/jobs/tier/calculate.ts): `apps/worker/src/jobs/tier/calculate.ts`

### Shared platform

- [Authentication state](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/auth/AuthStore.ts): `apps/web/src/features/auth/AuthStore.ts`
- [Web data client](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/lib/supabase.ts): `apps/web/src/lib/supabase.ts`
- **Supabase data**
- [Reading analytics](https://github.com/novanhleonard-sys/pln/blob/main/apps/web/src/features/analytics/useReadSessionTracker.ts): `apps/web/src/features/analytics/useReadSessionTracker.ts`
- [Adaptation requests](https://github.com/novanhleonard-sys/pln/blob/main/supabase/functions/request_adaptation/index.ts): `supabase/functions/request_adaptation/index.ts`
- [Contribution submission](https://github.com/novanhleonard-sys/pln/blob/main/supabase/functions/submit_contribution/index.ts): `supabase/functions/submit_contribution/index.ts`

### Other components

- **Reader / contributor**

## Connections

- Reader / contributor → Web routes: opens (evidence: `apps/web/src/main.tsx`)
- Web routes → Map discovery: routes to (evidence: `apps/web/src/main.tsx`)
- Web routes → Story reader: routes to (evidence: `apps/web/src/main.tsx`)
- Web routes → Contribution form: routes to (evidence: `apps/web/src/main.tsx`)
- Web routes → Reader profile: routes to (evidence: `apps/web/src/main.tsx`)
- Web routes → Admin workspace: routes to (evidence: `apps/web/src/main.tsx`)
- Web routes → Authentication state: initializes (evidence: `apps/web/src/main.tsx`)
- Map discovery → Supabase data: queries stories (evidence: `apps/web/src/features/map/useStories.ts`)
- Reader preferences → Supabase data: syncs preferences (evidence: `apps/web/src/features/reader/store/useReaderStore.ts`)
- Reader preferences → Supabase data: loads preferences
- Story reader → Reading analytics: tracks reading
- Reading analytics → Supabase data: upserts sessions (evidence: `apps/web/src/features/analytics/useReadSessionTracker.ts`)
- Story reader → Reader preferences: uses preferences
- Story reader → Adaptation experience: offers adaptation
- Story reader → Story audio mode: offers audio mode
- Contribution form → Story matching: checks matches (evidence: `apps/web/src/features/contribute/ContributeForm.tsx`)
- Contribution form → Supabase data: submits contribution
- Contribution form → Contribution submission: requests submission
- Contribution tracking → Supabase data: reads submissions
- Admin workspace → Admin dashboard: renders (evidence: `apps/web/src/features/admin/AdminCenter.tsx`)
- Admin workspace → Content editing: renders (evidence: `apps/web/src/features/admin/AdminCenter.tsx`)
- Admin workspace → AI style controls: renders (evidence: `apps/web/src/features/admin/AdminCenter.tsx`)
- Admin workspace → Region groups: renders (evidence: `apps/web/src/features/admin/AdminCenter.tsx`)
- Admin workspace → Voice library: renders (evidence: `apps/web/src/features/admin/AdminCenter.tsx`)
- Content editing → Supabase data: manages content
- Job worker → Processing stages: dispatches jobs (evidence: `apps/worker/src/index.ts`)
- Job worker → Tier calculation: runs tier check (evidence: `apps/worker/src/index.ts`)
- Processing stages → AI provider registry: requests generation (evidence: `apps/worker/src/stages/story-visual-bible/index.ts`)
- AI provider registry → AI budget guard: checks budget (evidence: `apps/worker/src/providers/registry.ts`)
- AI provider registry → Gemini provider: dispatches generation
- Job worker → Supabase data: polls jobs
- Processing stages → Supabase data: reads and writes records (evidence: `apps/worker/src/stages/story-visual-bible/index.ts`)
- Adaptation experience → Adaptation requests: requests adaptation
- Authentication state → Web data client: authenticates through (evidence: `apps/web/src/features/auth/AuthStore.ts`)
- Web data client → Supabase data: connects to (evidence: `apps/web/src/lib/supabase.ts`)
