Module map
Purpose
Orient an integrator or developer to the repo's top-level layout so they can answer "where does this change belong?" in under a minute. This is the companion to System overview, but at the directory level rather than the subsystem level.
Prerequisites
- Required: Familiarity with Node.js + React project layouts.
- Useful: A local clone of the repo to tab through while reading.
Inputs
- A change you want to make: a new ingestion source, a new signal type, a new UI surface, a new operational script, a new cross-cutting utility.
- The symptom you're debugging (if applicable): something in the UI, the API, or a CLI script.
Outputs
- A directory where the change belongs.
- A sense of what you should not change in the same PR to keep the blast radius small.
Constraints
- Keep business logic modular. A feature specific to WhatsApp goes under
business_modules/whatsapp/. If it touches news too, it's either two features or it belongs in a cross-cut module. - Keep cross-cutting concerns shared. Persistence, budget tracking, LLM clients — don't duplicate these per business module.
- UI presents, it does not compute. The React app renders data returned by the API. Analysis, normalization, and scoring live in the server modules.
- Scripts are interfaces, not logic. The
package.jsonscripts andscripts/*.share thin wrappers that call into the modules. Don't write significant logic in shell.
Top-level layout
/
├── app.js, server.js # Fastify app + entry point
├── package.json # Scripts + deps
├── openapi/openapi.yaml # API contract (source of truth)
├── product_docs/ # These docs (served in-app and by docs-site)
├── docs-site/ # Docusaurus site configured to read product_docs
├── scripts/ # Shell wrappers + validators
│ ├── daily-pipeline.sh # End-to-end daily run
│ └── docs/validate-docs.js # `npm run docs:check`
├── business_modules/
│ ├── news-sites/ # NewsAPI.ai + homefront extractor
│ ├── whatsapp/ # Meta Cloud API webhook + stores + export
│ ├── audio/ # Whisper transcription + markdown export
│ ├── video/ # YouTube / video ingest
│ ├── recording/ # Scheduled stream recorders
│ ├── radio/ # Radio station specifics
│ ├── resilience/ # Signal extraction + assessment
│ ├── translation/ # On-demand report translation
│ ├── chat/ # Follow-up chat grounded in reports
│ ├── edu, education/ # Education ministry data
│ ├── pbo_report_muni/ # Municipality data
│ ├── naftali/ # Political figure activity
│ ├── survey/ # Survey analysis
│ └── docs/ # In-app docs surface helpers (if present)
├── cross-cut-modules/
│ ├── budget/ # Cost accounting, caps, cost-log
│ └── ... # Persistence helpers, LLM clients, shared utils
├── client/
│ └── src/ # React SPA (Docs panel, dashboards, tabs)
├── tests/ # node --test suite
└── utils/ # Small shared server utilities (e.g. productDocs.js)
Examples
I want to add a new ingestion source
- Create
business_modules/<source>/withinput/for CLI entry points and areports/orarticles_extracted/dir for dated markdown exports. - Match the markdown format downstream extraction expects — look at
business_modules/news-sites/articles_extracted/for a reference. - Add an
npm runscript inpackage.jsonpointing at your entry point. - (If using an LLM) route calls through the cross-cut LLM client so budget tracking works out of the box.
- Write a guide under
product_docs/guides/describing how to use it.
I want to add a new signal type
- Update the taxonomy (list of allowed
signal_typevalues) inbusiness_modules/resilience/. - Add the type to the extraction prompt's allowed values.
- Add a weight for it in the signal→component mapping.
- Decide whether to backfill older days — rerunning extraction lets old reports surface the new type.
- Bump whatever version / changelog you use; silent taxonomy changes create silent score drift.
I want a new tab in the UI
- Create a component under
client/src/components/<YourTab>.jsxwith its own CSS module. - Expose data via a new API route in
app.jsthat delegates to abusiness_modules/<domain>/module. - Wire the tab into
client/src/MainApp.jsx— add it to theTABSarray and the switch that renders tab content. - Add translations for the tab label in the language context.
- If the tab should appear in the Docs panel, write a guide in
product_docs/guides/— the panel picks it up automatically.
I want a new CLI operation
- Put the entry point in the relevant business module's
input/directory. - Add an
npm run <name>script that invokes it. - Include it (or document inclusion) in
scripts/daily-pipeline.shif it's a regular daily step. - Treat env vars as the input contract — document them in the command's README or in the doc guide that references it.
I need a new cross-cutting utility
- Criterion: two or more business modules would otherwise copy the same code.
- Location:
cross-cut-modules/<concern>/with clean entry points. - Don't: hide business logic here. If only one module uses it, it belongs in that module.
Troubleshooting
- Not sure where to add a new adapter
- Check: is it ingestion (source adapter) or analysis (signals / scoring)?
- Fix: add ingestion under its own
business_modules/<source>/; keep scoring and taxonomy inbusiness_modules/resilience/.
- My feature ended up spanning five directories
- Check: whether the feature is actually several features, or whether you're touching cross-cut utilities.
- Fix: split the PR. Cross-cut changes ship on their own; each business module change rides on top.
- UI code has grown a private understanding of signals
- Check: whether the client is parsing or reshaping analysis output.
- Fix: move that shape-logic into the API response. The client should consume ready-to-render data.