167 lines
6.8 KiB
Markdown
167 lines
6.8 KiB
Markdown
# 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), with `config.py` as 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.vue` or 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.json` for 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/`)
|
|
```js
|
|
// 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 from `models` and `utils`; `models` and `utils` never
|
|
import from `services` or `api`.
|
|
- 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 `Task` and is polled. Don't introduce ad-hoc
|
|
status fields on `Project`; extend `Task`.
|
|
- **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 call `subprocess` /
|
|
pipe primitives elsewhere.
|
|
- **Configuration is centralized.** New tunables go in
|
|
`backend/app/config.py` (and an `.env.example` line 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 new `zep_*` files.
|
|
|
|
---
|
|
_Document patterns, not file trees. New files following patterns shouldn't require updates_
|