diff --git a/AGENTS.md b/AGENTS.md index 916e3d051..11667016e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,7 +10,13 @@ |------|---------|-------| | `src/backend/` | FastAPI + Celery Workers + Linsight Worker | Python 3.11+, uv, SQLModel, LangGraph | | `src/frontend/platform/` | Admin / builder UI | Vite 5 + **Zustand** + react-query v3 + bs-ui | -| `src/frontend/client/` | End-user chat UI (`/workspace` base path) | Vite 6 + **Recoil** + react-query v5 + shadcn/ui | +| `src/frontend/client/` | End-user chat UI (`/workspace` base path) | Vite 6 + **Recoil** + react-query v4 (@tanstack) + shadcn/ui | + +**Runtime topology** (full picture → `docs/architecture/01-architecture-overview.md`): +- Two SPAs — platform (:3001) and client (:4001, base `/workspace`) — call FastAPI (:7860): `/api/v1` frontend-facing, `/api/v2` open RPC. Commercial edition inserts a Java gateway in front (→ `architecture/11-gateway.md`). +- Async work: Celery workers (knowledge / workflow / default queues) + Beat; the Linsight agent runs as an independent worker process fed by a Redis queue. +- Storage ×6: MySQL|DM8 (dual-DB law C2), Redis, Milvus + ES (RAG dual recall), MinIO, OpenFGA (ReBAC). +- Cross-cutting: tenant isolation auto-injected via ContextVar (C3); every permission check goes through PermissionService → OpenFGA (C4). --- @@ -33,12 +39,13 @@ Middleware (MySQL / Redis / Milvus / ES / MinIO / OpenFGA): integration tests ru Two React apps that **must not be mixed**. Per-app rules auto-load from each sub-project's `AGENTS.md`: - `src/frontend/platform/AGENTS.md` — Admin/builder UI (Zustand, react-query v3, bs-ui, `@/`) -- `src/frontend/client/AGENTS.md` — End-user chat UI (Recoil, react-query v5, shadcn, `~/`) +- `src/frontend/client/AGENTS.md` — End-user chat UI (Recoil, react-query v4, shadcn, `~/`) -**Hard rules (both apps):** +**Hard rules (both apps — single source of truth here; per-app files add only app-specific detail):** - TypeScript only (`.ts` / `.tsx`); functional components only; no class components. - Single file ≤ 600 lines. Extract sub-components or hooks when exceeded. -- `interface` for Props; `type` for internal types. `handleXxx` internal handlers / `onXxx` props. +- `interface` for Props; `type` for internal types. `handleXxx` internal handlers / `onXxx` props. PascalCase components, camelCase utilities/hooks. +- Named exports for components (`export function`); no default exports. Minimize `any` — if unavoidable, `// eslint-disable-next-line` + a one-line reason. - **Never** `import axios` directly — use the wrapped request module. (store must not call HTTP = constitution **C7**) - **Never** introduce new UI or state-management libraries. - All code comments in English. @@ -58,7 +65,8 @@ The 8 RULEs are the machine-enforcement arm of constitution **C1 / C4 / C6 / C7* **Full guide — track selection, ★ pause points, deviation re-confirm rule, document roles, constitution gate, harness → [`docs/SDD-Guide.md`](docs/SDD-Guide.md).** ``` -0. release-contract.md + read constitution.md +0. release-contract.md (features/v{X.Y.Z}/release-contract.md; + version's first feature creates it) + read constitution.md 1. Spec Discovery → ★ user confirms 2. spec.md → /sdd-review spec → ★ user confirms 3. design.md → /sdd-review design → ★ user confirms (Constitution Check) @@ -70,7 +78,7 @@ The 8 RULEs are the machine-enforcement arm of constitution **C1 / C4 / C6 / C7* 9. merge ``` -Artifacts: `features/v{X.Y.Z}/{NNN}-{name}/{spec,design,tasks}.md`. Templates: `features/_templates/`. +Artifacts: `features/v{X.Y.Z}/{NNN}-{name}/{spec,design,tasks}.md`. Templates: `features/_templates/` (incl. `release-contract.md`). **★ cannot be skipped.** Trivial/hotfix changes use a lighter track — see SDD-Guide §1. Tests: new backend tests under `test//` (e.g., `test/approval/`), not `test/` root. `asyncio_mode=auto`. @@ -79,7 +87,7 @@ Tests: new backend tests under `test//` (e.g., `test/approval/`), not `t ## 7. Common Pitfalls -Runtime/deploy pitfalls (MinIO `sharepoint`, Celery Beat × multi-tenant, DB config Redis TTL) → `src/backend/AGENTS.md`. Commercial edition (`BISHENG_PRO` env, gateway proxy, SSO) → `docs/architecture/11-gateway.md`. +Backend runtime pitfalls (tenant-filter SELECT-only gap, ruff hook import trap, Celery Beat × multi-tenant, DB config Redis TTL) → `src/backend/AGENTS.md` §Known Pitfalls. MinIO `sharepoint` image-proxy pitfall → `src/frontend/platform/AGENTS.md` §Known Pitfalls. Commercial edition (`BISHENG_PRO` env, gateway proxy, SSO) → `docs/architecture/11-gateway.md`. | Pitfall | Reality | |---------|---------| @@ -91,6 +99,9 @@ Runtime/deploy pitfalls (MinIO `sharepoint`, Celery Beat × multi-tenant, DB con ## 8. Reference +- **Docs index** → `docs/README.md` (navigation hub); onboarding & testing → `docs/architecture/09-development-guide.md` - **Architecture docs** → `docs/architecture/` (overview, permission, gateway, multi-tenant, data-models, …) - **Skills**: `/sdd-review`, `/task-review`, `/code-review`, `/e2e-test`, `/i18n-localizer`, `/react-component-refactor` +**Instruction files (AGENTS.md map).** Root = this file, loaded every session. Auto-loaded on top when editing the matching directory: `src/backend/`, `src/frontend/platform/`, `src/frontend/client/`, plus deep-dir specials `src/backend/bisheng/core/database/alembic/` (migrations) and `src/backend/scripts/` (one-off scripts). Every `CLAUDE.md` is a symlink to its sibling `AGENTS.md` — edit `AGENTS.md` only. Put a new rule in the deepest file covering its scope (cross-app / cross-module → this file; app- or dir-specific → the nearest file); never duplicate a rule across levels — it *will* drift. + diff --git a/docs/README.md b/docs/README.md index b71c30059..948da5483 100644 --- a/docs/README.md +++ b/docs/README.md @@ -23,14 +23,7 @@ | 目录 | 内容 | |------|------| | [`api/`](api/) | 接口文档(filelib 纯检索、知识空间/知识库接口) | -| [`qa/`](qa/) | 本地测试数据备忘(星辰公司组织结构与账号) | -| [`私有化部署/`](私有化部署/) · [`商业拓展套件gateway部署说明/`](商业拓展套件gateway部署说明/) | 部署文档 | +| [`PRD/`](PRD/) | 现行迭代的产品 PRD 与技术方案(按 `{版本} {主题} PRD/` 组织) | +| [`observability/`](observability/) | BS_METRIC 指标日志契约(监控团队解析依据) | +| [`私有化部署/`](私有化部署/) | 部署文档 | | [`blog/`](blog/) | 设计科普(如"企业权限体系的前世今生") | - -## 历史(仅供追溯,非现行规范) - -[`archive/`](archive/): -- `2.5 权限管理体系改造 PRD/` — v2.5 多租户/权限改造的完整 PRD、技术方案、运维手册(已实现,移此归档) -- `2.5-review-process/` — v2.5 权限/ReBAC review 过程文档、迁移排查、代码质量报告 -- `cleanup-tasks/` — 各类"移除/清理"任务清单(org_sync、默认用户组) -- `legacy-sdd/` — 旧 SDD 的 spec/plan(达梦支持、文件解析调度等;现已被 `features/` + `SDD-Guide.md` 取代) diff --git a/src/backend/AGENTS.md b/src/backend/AGENTS.md index 04d7607b5..ac95129a0 100644 --- a/src/backend/AGENTS.md +++ b/src/backend/AGENTS.md @@ -68,7 +68,7 @@ Applies to async (`asyncio.gather(..., return_exceptions=True)` results must be ```bash # Dependencies (uv, lockfile = uv.lock, Python must be 3.11.x — pyproject requires-python >=3.11) -uv sync --frozen --python uv run python +uv sync --frozen # Tests uv run pytest test/ # all @@ -94,7 +94,7 @@ uv run celery -A bisheng.worker.main beat -l info # Linsight Worker (optional) uv run python bisheng/linsight/worker.py --worker_num 4 --max_concurrency 5 -# DB migration (alembic.ini in src/backend/) +# DB migration (alembic.ini in src/backend/; revisions live in bisheng/core/database/alembic/versions/) uv run alembic upgrade head uv run alembic revision --autogenerate -m "msg" # autogen reflects MySQL only; review DM8 compat manually ``` @@ -103,28 +103,35 @@ uv run alembic revision --autogenerate -m "msg" # autogen reflects MySQL only; **Migration vs. script — keep them separate:** -- **Schema changes** (DDL: create/alter/drop table, columns, indexes, constraints) → Alembic revision under `migrations/versions/`. These are versioned and replayed on every environment via `alembic upgrade head`. +- **Schema changes** (DDL: create/alter/drop table, columns, indexes, constraints) → Alembic revision under `bisheng/core/database/alembic/versions/`. These are versioned and replayed on every environment via `alembic upgrade head`. - **One-off data migration or cleanup** (backfill/transform rows, purge stale data, fix-up jobs run once) → a standalone script under `scripts/`, **not** Alembic. Don't bury data-only operations in schema revisions. --- ## Quick Map (indexes — architecture detail in `docs/architecture/`) -**Domain modules** (own top dir + `api/` + `domain/`): knowledge, workflow, permission, linsight, llm, chat_session, tool, channel, message, user, finetune, share_link, telemetry_search, workstation, open_endpoints, mcp_manage. -**Non-standalone** (routes under `api/v1/`, no top dir): assistant, evaluation, audit, group, tag, mark, flows, skillcenter, variable, report, invite_code. +**Domain modules** — convention: own top dir under `bisheng/` with `api/` + `domain/` (knowledge, linsight, permission, approval, tenant, evaluation, llm, chat_session, …). `ls bisheng/` is the authoritative list — do not maintain a full enumeration here, it rots. Structural exceptions: `workflow/` (engine layout: graph/nodes/edges, no api/domain) and `mcp_manage/` (clients/langchain only). +**Non-standalone** (single-file routes under `api/v1/`, no top dir): assistant, audit, group, tag, mark, flows, skillcenter, variable, report, invite_code, plus legacy chat/dataset/endpoints. → responsibilities: `architecture/02-backend-modules.md`. -**API routes**: v1 `/api/v1` (29 routes, frontend-facing); v2 RPC `/api/v2` (6 routes, in `open_endpoints/api/`). +**API routes**: v1 `/api/v1` (frontend-facing) + v2 RPC `/api/v2` (in `open_endpoints/api/`) — authoritative registry: `bisheng/api/router.py`. **Subsystems** (quick entry points; architecture in the linked doc): -- **Workflow engine** — LangGraph DAG. Key files `workflow/graph/{graph_engine,graph_state,workflow}.py`, `nodes/node_manage.py`. 14 node types. Add node = enum in `workflow/common/node.py` + node class under `workflow/nodes//` (inherit `BaseNode`) + register in `NODE_CLASS_MAP`. → `architecture/03` +- **Workflow engine** — LangGraph DAG. Key files `workflow/graph/{graph_engine,graph_state,workflow}.py`, `nodes/node_manage.py`. Node types = `NodeType` enum in `workflow/common/node.py`. Add node = enum member + node class under `workflow/nodes//` (inherit `BaseNode`) + register in `NODE_CLASS_MAP` (`node_manage.py`). → `architecture/03` - **Knowledge/RAG** — Load → Transform → Ingest; Milvus (dense) + ES (sparse) dual write; async via `knowledge_celery`. Core: `knowledge/rag/pipeline/base.py`. → `architecture/04` - **Linsight agent** — independent Worker via Redis queue. `linsight/worker.py`, `linsight/domain/task_exec.py`. → `architecture/05` - **Permission** (ReBAC / OpenFGA) → `architecture/10` (+ constitution C4) - **Multi-tenant** → `architecture/12` (+ constitution C3) - **Gateway** (commercial) → `architecture/11` +- **Approval center (F025)** — `approval/` (domain module) + `worker/approval/` (outbox exec) + `notification/` (in-app messages). Read the `approval-module` skill before touching it. -**Key enums**: `FlowType` ASSISTANT=5, WORKFLOW=10, WORKSTATION=15, LINSIGHT=20, CHANNEL_ARTICLE=25, KNOWLEDGE_SPACE=30. File states: WAITING(5)→PROCESSING(1)→SUCCESS(2)/FAILED(3)/TIMEOUT(6). → models detail: `architecture/07-data-models.md` + `数据库表结构与关联说明.md`. +**Cross-cutting dirs** (not domain modules; touched constantly): +- `core/` — config loading, Alembic migrations (`core/database/alembic/versions/`), tenant ContextVar (`core/context/tenant.py`), OpenFGA client (`core/openfga/manager.py`) +- `common/` — `resp_*`/pagination schemas (`common/schemas/api.py`), error codes (`common/errcode/`), auth deps (`common/dependencies/`) +- `database/models/` — legacy ORM layer; many live models (e.g. `FlowType`) are here, not in domain modules +- `worker/` — Celery task tree (knowledge, workflow, approval, telemetry, …); app entry `worker/main.py` + +**Key enums**: `FlowType` (`database/models/flow.py`) ASSISTANT=5, WORKFLOW=10, WORKSTATION=15, LINSIGHT=20, CHANNEL_ARTICLE=25, KNOLEDGE_SPACE=30 (member name is misspelled in code — no W; grep accordingly). File states: WAITING(5)→PROCESSING(1)→SUCCESS(2)/FAILED(3)/TIMEOUT(6). → models detail: `architecture/07-data-models.md` + `architecture/数据库表结构与关联说明.md`. **Celery queues**: `knowledge_celery` (20 threads, doc parse/embed/vector), `workflow_celery` (100, DAG exec), `celery` default (100, telemetry). Beat iterates all active tenants per task. @@ -134,6 +141,15 @@ uv run alembic revision --autogenerate -m "msg" # autogen reflects MySQL only; --- +## Known Pitfalls + +- **Tenant auto-filter only intercepts SELECT.** The `do_orm_execute` listener (`core/database/tenant_filter.py`) returns early for non-SELECT; `before_flush` auto-fills `tenant_id` on INSERT. Bulk `update()` / `delete()` statements and raw `text()` SQL get **no** tenant injection — hand-write the `tenant_id` condition (has leaked cross-tenant twice: LLM module, F035). +- **The ruff PostToolUse hook deletes not-yet-used imports.** Every written `.py` gets `ruff check --fix`; an import added in one edit whose usage lands only in a later edit is removed as unused (F401) in between. Land import + usage in the same edit, or write the usage first. +- **Celery Beat × multi-tenant.** A Beat schedule fires once; the task body iterates all active tenants — call `set_current_tenant_id()` per iteration, and wrap the cross-tenant enumeration query itself in `bypass_tenant_filter()` (`core/context/tenant.py`), otherwise queries fail on missing tenant context. +- **DB config changes take up to 100s.** DB-layer config is cached in Redis with a 100s TTL — don't chase "config not applied" inside that window. + +--- + ## Entry Points - `main.py` — FastAPI app creation + lifespan diff --git a/src/frontend/client/AGENTS.md b/src/frontend/client/AGENTS.md index 27fc0f253..18edce0e0 100644 --- a/src/frontend/client/AGENTS.md +++ b/src/frontend/client/AGENTS.md @@ -1,7 +1,7 @@ # Frontend Rules — Client (End-user Chat UI) Auto-loaded when editing files in `src/frontend/client/`. Base path: `/workspace`. -Cross-app boundary + hard rules common to both apps: root `AGENTS.md §4`. The store-must-not-call-HTTP law: `docs/constitution.md` C7 (arch-guard RULE-6). +Cross-app boundary + hard rules common to both apps: root `AGENTS.md §4` (single source — not repeated here). The store-must-not-call-HTTP law: `docs/constitution.md` C7 (arch-guard RULE-6). ## Commands (cwd: `src/frontend/client/`) @@ -11,19 +11,15 @@ npm run dev # dev server on :4001 ``` ## Tech Stack -Vite 6 + React 18 + TypeScript + TailwindCSS 3 + Radix UI (shadcn/ui) + **Recoil** + **react-query v5** + react-i18next + react-router-dom v6 + **lucide-react** + axios (wrapped in `~/api/request.ts`) +Vite 6 + React 18 + TypeScript + TailwindCSS 3 + Radix UI (shadcn/ui) + **Recoil** + **react-query v4 (@tanstack)** + react-i18next + react-router-dom v6 + **lucide-react** + axios (wrapped in `~/api/request.ts`) -## Mandatory Rules -- **TypeScript only**: all new files `.ts` / `.tsx`. -- **Functional Components**: hooks only; class components prohibited. +## Mandatory Rules (client-specific — common hard rules in root §4) - **Path Aliases**: `~/` (or `@/`) → `src/`. -- **HTTP Requests**: must use `~/api/request.ts`; never import `axios` directly. +- **HTTP Requests**: wrapper is `~/api/request.ts`. - **State Management**: Recoil (`~/store/`). Context or other solutions prohibited for new state. -- **UI Components**: `~/components/ui/` (shadcn / Radix-based). No new UI libraries. +- **UI Components**: `~/components/ui/` (shadcn / Radix-based). - **Icons**: prefer `bisheng-icons` — `import { Outlined } from 'bisheng-icons'` → `` (variants `Outlined` / `Filled` / `Colored`). Use `lucide-react` ONLY as a fallback when `bisheng-icons` has no matching-semantic icon. - **⚠️ After upgrading `bisheng-icons`**, clear the Vite pre-bundle cache or new icons crash the page (`Element type is invalid`): `npm run dev -- --force` (or `rm -rf node_modules/.vite && npm run dev`). Its git-source `exports` field defeats Vite's dep-change detection, so the stale pre-bundled snapshot is served unless forced. -- **Code Comments**: English. -- **Component Size**: < 600 lines; extract sub-components or hooks when exceeded. - **Toast**: `const { showToast } = useToastContext(); showToast?.({ message, severity: 'error' | 'success' })`. - **i18n**: `useLocalize()` from `~/hooks` → `localize()`. Locale files at `src/locales/{en,zh-Hans,ja}/translation.json` (single file). New keys use nested namespace format (see `/i18n-localizer` skill). - **Brand theme (blue⇄green)**: brand-colored UI MUST follow the theme — **never hardcode brand hex** (`#165DFF`/`#024DE3`/`#19B476`/`#187C54`…). @@ -33,12 +29,3 @@ Vite 6 + React 18 + TypeScript + TailwindCSS 3 + Radix UI (shadcn/ui) + **Recoil - **Illustrations**: inline SVG, `fill`/`stroke` = `rgb(var(--illus-NNN))` (separate brighter palette, in `src/components/illustrations/`). SVG presentation attrs ignore `var()` → use inline `style`/className/CSS-mask, and `useId()` to dedupe gradient/clip ids. - **Do NOT theme**: semantic colors (success `#00b42a` / danger `#f53f3f` / warning `#ff7d00`), type colors (skill-purple, assistant-orange), third-party logos. Need a muted-but-themed brand color → `rgb(var(--brand-muted))`. - Full guide: `BRAND-THEME-HANDOFF.md`. - -## Coding Style -- **Naming**: `interface` for Props; `type` for internal types. PascalCase components, camelCase utilities/hooks. -- **Event Handling**: `handleXxx` for internal logic, `onXxx` for props. -- **Any Type**: minimize; if necessary add `// eslint-disable-next-line` with a brief reason. -- **Exports**: named exports (`export function`); no default exports for components. - -## Known Pitfalls -- **403 Errors**: handled automatically in the response interceptor with redirection. No manual handling needed in business logic. diff --git a/src/frontend/platform/AGENTS.md b/src/frontend/platform/AGENTS.md index 447fd558b..b088ef208 100644 --- a/src/frontend/platform/AGENTS.md +++ b/src/frontend/platform/AGENTS.md @@ -1,7 +1,7 @@ # Frontend Rules — Platform (Admin / Builder UI) Auto-loaded when editing files in `src/frontend/platform/`. -Cross-app boundary + hard rules common to both apps: root `AGENTS.md §4`. The store-must-not-call-HTTP law: `docs/constitution.md` C7 (arch-guard RULE-6). +Cross-app boundary + hard rules common to both apps: root `AGENTS.md §4` (single source — not repeated here). The store-must-not-call-HTTP law: `docs/constitution.md` C7 (arch-guard RULE-6). ## Commands (cwd: `src/frontend/platform/`) @@ -14,26 +14,16 @@ VITE_PROXY_TARGET=http://localhost:8180 npm start -- --host 0.0.0.0 # commercia ## Tech Stack Vite 5 + React 18 + TypeScript + TailwindCSS 3 + Radix UI (bs-ui) + **Zustand** + React Context + **react-query v3** + react-i18next + react-router-dom v6 + **@xyflow/react** + axios (wrapped in `@/controllers/request.ts`) -## Mandatory Rules -- **TypeScript only**: all new files `.ts` / `.tsx`. -- **Functional Components**: hooks only; class components prohibited. +## Mandatory Rules (platform-specific — common hard rules in root §4) - **Path Aliases**: `@/` → `src/`. -- **HTTP Requests**: must use `@/controllers/request.ts`; never import `axios` directly. API modules in `@/controllers/API/`. -- **State Management**: Zustand stores in `@/store/` (cross-page); React Context (`@/contexts/`) for UI-scoped state (alerts, theme, tabs). No new state libraries. -- **UI Components**: `@/components/bs-ui/` (Radix-based). Icons from `@/components/bs-icons/`. No new UI libraries. +- **HTTP Requests**: wrapper is `@/controllers/request.ts`; API modules in `@/controllers/API/`. +- **State Management**: Zustand stores in `@/store/` (cross-page); React Context (`@/contexts/`) for UI-scoped state (alerts, theme, tabs). +- **UI Components**: `@/components/bs-ui/` (Radix-based). Icons from `@/components/bs-icons/`. - **Workflow editor**: `@xyflow/react` (**not** `react-flow-renderer`); nodes in `src/CustomNodes/`. -- **Code Comments**: English. -- **Component Size**: < 600 lines; extract sub-components or hooks when exceeded. - **Toast**: `import { toast } from "@/components/bs-ui/toast/use-toast"; toast({ title, variant: 'error' | 'success', description })`. - **Confirm Dialogs**: `import { bsConfirm } from "@/components/bs-ui/alertDialog/useConfirm"`. - **i18n**: `useTranslation()` from react-i18next → `t()`. Locale files at `public/locales/{en-US,zh-Hans,ja}/{ns}.json`. Namespaces: bs, flow, model, tool, dashboard, knowledge. -## Coding Style -- **Naming**: `interface` for Props; `type` for internal types. PascalCase components, camelCase utilities/hooks. -- **Event Handling**: `handleXxx` for internal logic, `onXxx` for props. -- **Any Type**: minimize; if necessary add `// eslint-disable-next-line` with a brief reason. -- **Exports**: named exports (`export function`); no default exports for components. - ## API Layer Pattern ```typescript // @/controllers/API/xxx.ts @@ -49,5 +39,4 @@ captureAndAlertRequestErrorHoc(getSomething()).then(res => { ... }) ``` ## Known Pitfalls -- **403 Errors**: handled automatically in the response interceptor. No manual handling needed. - **MinIO Image Proxy**: Vite `fileServiceTarget` must match backend `config.yaml` `object_storage.minio.sharepoint`, otherwise image requests get 403.