6.8 KiB
Project Structure
Organization Philosophy
A monorepo split by runtime (backend/ Python, frontend/ Vue),
with each side organized by layer:
- Backend:
api/(HTTP) →services/(logic) →models/(state) →utils/(cross-cutting helpers), withconfig.pyas the single source of configuration. - Frontend:
views/(route-level pages) →components/(reusable UI) →api/(HTTP services) →store/,router/,i18n/,assets/.
The core workflow is pipeline-shaped (5 sequential steps), and the codebase mirrors that: each step has a backend service or service group, a Flask blueprint endpoint, a frontend Step component, and (where useful) a route-level view.
Directory Patterns
Backend HTTP Layer
Location: backend/app/api/
Purpose: One Flask blueprint per pipeline domain — thin handlers
that validate input, dispatch to services, and return JSON. No business
logic.
Files: graph.py (graph_bp), simulation.py (simulation_bp),
report.py (report_bp).
Backend Services
Location: backend/app/services/
Purpose: All business logic. Each file owns one responsibility
(graph build, profile generation, simulation runner, report agent, etc.).
Pattern: Long-running operations expose an async/background entrypoint
that returns a Task and runs work off the request thread. Direct calls
to Neo4j, OASIS subprocesses, or LLM streaming live here, not in api/.
Naming note: Files prefixed zep_* are legacy from the Zep→Graphiti
migration. Don't rename casually (imports across the project), and don't
add new zep_* files.
Backend State Models
Location: backend/app/models/
Purpose: In-memory, JSON-serializable state objects. Project
tracks per-project pipeline state and group_id; Task tracks
background-job status, progress, and result. These are the polling
contract with the frontend — change their shape with care.
Backend Utilities
Location: backend/app/utils/
Purpose: Cross-cutting helpers usable from any service —
LLM client wrapper (llm_client.py), file parsing (file_parser.py),
retry (retry.py), logging (logger.py), locale (locale.py),
pagination helpers (zep_paging.py).
Rule: Utils never import from services/ or api/.
Backend Config
Location: backend/app/config.py
Purpose: Single file for LLM, Neo4j, embedding, chunking, OASIS,
and ReportAgent parameters. Read env vars here; consume the resulting
constants elsewhere. Avoid os.getenv calls scattered through services.
Frontend Views (Routes)
Location: frontend/src/views/
Purpose: Page-level components mapped to routes (Home.vue,
MainView.vue, Process.vue, SimulationView.vue,
SimulationRunView.vue, InteractionView.vue, ReportView.vue).
Pattern: Process.vue is the workflow orchestrator (~50KB); it
composes the Step components and owns step transitions.
Frontend Components
Location: frontend/src/components/
Purpose: Reusable UI. Step components (Step1GraphBuild.vue,
Step2EnvSetup.vue, Step3Simulation.vue, Step4Report.vue,
Step5Interaction.vue) implement one pipeline stage each;
GraphPanel.vue renders the D3 knowledge graph;
HistoryDatabase.vue, LanguageSwitcher.vue are general-purpose.
Frontend API Services
Location: frontend/src/api/
Purpose: Axios services that wrap the backend blueprints —
graph.js, simulation.js, report.js, with index.js as the shared
client (5-min timeout, exponential retry).
Rule: Components and views call these services; they do not import
axios directly. New endpoints add a method on the matching service.
Locales (shared)
Location: /locales/ at repo root
Purpose: i18n source for both frontend (vue-i18n) and backend
(logger). Vite aliases @locales to this folder. Files: en.json,
zh.json, languages.json.
Static Assets
Location: static/ at repo root
Purpose: Images and demo assets referenced from READMEs (logos,
screenshots, video covers). Not bundled by Vite.
Naming Conventions
- Python files / modules / functions / vars:
snake_case - Python classes:
PascalCase - Python constants:
UPPER_SNAKE_CASE - Vue Single-File Components:
PascalCase.vue - Vue route views:
<Name>View.vueor domain noun (Home.vue,Process.vue,MainView.vue) - Vue step components:
Step<N><Name>.vue(matches the pipeline stage) - Frontend non-component JS:
camelCase.js(e.g.pendingUpload.js) - Locale files: lowercase ISO code (
en.json,zh.json) +languages.jsonfor the language list - Booleans (Python and JS): prefix with
is_/has_/should_where it improves clarity, but match local style first
Import Organization
Frontend (frontend/src/)
// Vendor
import { ref, computed } from 'vue'
import axios from 'axios'
// Absolute (via @ alias)
import GraphPanel from '@/components/GraphPanel.vue'
import { fetchGraph } from '@/api/graph'
// Locales (shared with backend)
import en from '@locales/en.json'
// Relative (same feature only)
import { useStep } from './useStep'
Path aliases (vite.config.js):
@/→frontend/src/@locales→ repo-root/locales/
Backend (backend/app/)
- Use absolute package imports (
from app.services.graph_builder import ...). - Layer dependency rule:
api → services → models / utils. Services may import frommodelsandutils;modelsandutilsnever import fromservicesorapi. - All Neo4j/Graphiti access goes through
services/graphiti_adapter.py.
Code Organization Principles
- Pipeline-aligned modules. When adding a new pipeline-touching feature, place code in the same backend service group and the same frontend Step component as the stage it belongs to. Don't split a stage across multiple services unless responsibilities genuinely diverge.
- Background tasks are uniform. Any operation taking more than a
few seconds returns a
Taskand is polled. Don't introduce ad-hoc status fields onProject; extendTask. - Per-project isolation. Every graph operation must filter by
group_id. Cross-project reads are out of scope and should be flagged in review. - IPC has one door. Subprocess communication for the simulator goes
through
services/simulation_ipc.py. Do not callsubprocess/ pipe primitives elsewhere. - Configuration is centralized. New tunables go in
backend/app/config.py(and an.env.exampleline if env-driven), not as constants scattered through services. - Legacy filenames stay.
zep_*files predate the Graphiti migration; leave the names alone to avoid touching every importer, but don't add newzep_*files.
Document patterns, not file trees. New files following patterns shouldn't require updates