From a6ef1da9bc1ff923e47f6cc1a89663abfe227bfb Mon Sep 17 00:00:00 2001 From: XingfenD Date: Tue, 11 Aug 2026 19:59:18 +0800 Subject: [PATCH] update docs --- AGENTS.md | 92 +++++++++ docs/README.md | 483 ++++++++++++++++++++++++++++++++++++++++++++++ docs/README_zh.md | 483 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1058 insertions(+) create mode 100644 AGENTS.md create mode 100644 docs/README.md create mode 100644 docs/README_zh.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..c57f04f --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,92 @@ +# AGENTS.md — backend + +## Module & Layout + +Go module: `github.com/XingfenD/yoresee_doc` (rooted at `backend/`). + +``` +cmd/main.go — API server entry (Connect RPC) +cmd/migrate/ — GORM AutoMigrate (runs first on startup) +cmd/db_init/ — seed data (admin user, default groups, templates…) +cmd/es_init/ — Elasticsearch index setup +cmd/notification-worker/ — RabbitMQ consumer +cmd/search-sync-worker/ — RabbitMQ consumer +cmd/snapshot-worker/ — RabbitMQ consumer (Yjs snapshot persistence) + +internal/ + bootstrap/ — chain-style Initializer (config → infra → repos → services) + config/ — Viper TOML loader; GlobalConfig singleton + transport/connectserver/ — HTTP mux, Connect RPC handler wiring, auth interceptor, CORS + transport/grpcserver/ — per-service RPC implementations (calls into service layer) + service/_service/ — business logic; package-level singletons (*Svc) + service/interface/ — service interfaces + MQ consumer contract + service/mq_service/ — MQ abstraction init (RabbitMQ) + repository/_repo/ — GORM queries; constructed via repository.NewRepositories() + model/ — GORM model definitions (16 models) + dto/ mapper/ types/ — transfer objects, mapping helpers, domain types + status/ — typed error codes (status.GenErrWithCustomMsg) + +pkg/ + storage/ — infra clients: DB, KVS (Redis), MinioClient, ES, Consul (package-level globals) + mq/ — MQ interface + RabbitMQ impl + cache/ lock/ key/ — shared cache keys, distributed lock, cache helpers + errs/ constant/ — shared errors and constants + gen/ — GENERATED protobuf Go stubs (gitignored) +``` + +## Build & Run + +```bash +# Full dev stack (from repo root): +bash deploy/script/start.sh dev up + +# Run backend only (after infra is up): +go run ./cmd/main.go + +# Run individual workers: +go run ./cmd/snapshot-worker +go run ./cmd/notification-worker +go run ./cmd/search-sync-worker + +# Migrate + seed (runs automatically in container): +go run ./cmd/migrate && go run ./cmd/db_init && go run ./cmd/es_init +``` + +No Makefile, no tests, no linter config. Verify with `go build ./...` and `go vet ./...`. + +## Config + +- File: `config.toml` (gitignored) — generated from `config.toml.tmpl` by `deploy/script/prepare.sh` +- Format: TOML, loaded by Viper with `${ENV_VAR}` substitution +- Env vars defined in `deploy/.env` (template: `deploy/.env.example`) +- Access via `config.GlobalConfig.*` + +## Startup Order + +Container CMD: `migrate → db_init → es_init → main` +Workers are separate binaries with their own bootstrap chains. + +## Key Patterns + +- **Connect RPC** (not raw gRPC server): handlers in `connectserver/handlers.go` wrap `grpcserver/*` implementations +- **Two HTTP listeners**: gRPC on `grpc_port` (9090), gRPC-web on `grpc_web_port` (8080); both use h2c +- **Auth interceptor**: JWT-based; allowlist for Login, Register, Health, SystemInfo +- **Service singletons**: `auth_service.AuthSvc`, `document_service.DocumentSvc`, etc. — set in `service.Init()` +- **Global infra**: `storage.DB`, `storage.KVS`, `storage.MinioClient`, `storage.ES`, `storage.Consul` +- **Migration**: GORM `AutoMigrate` (schema from model structs) + raw SQL for Postgres extensions (`ltree`) and indexes +- **DB seeding**: `cmd/db_init/` creates admin user, default permissions, templates, user groups +- **Elasticsearch**: optional — `InitElasticsearchAllowFail` degrades gracefully +- **Consul**: required — `RequireConsulEnabled` fatals if disabled +- **MQ**: RabbitMQ via `pkg/mq`; workers consume topics registered through `mq_service` + +## Protobuf Codegen + +Single proto: `proto/yoresee_doc/v1/yoresee_doc.proto` +Generated Go code: `pkg/gen/` (gitignored) +Regenerate: `bash deploy/script/gen_proto.sh` (from repo root) + +## Health Endpoints + +- `/health` — liveness +- `/readyz` — readiness (checks DB + Redis) +- `/livez` — liveness alias diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..6e498a3 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,483 @@ +# Yoresee Doc Backend + +Backend service for the Yoresee Doc collaborative document management platform, built with Go and Connect RPC. + +## Overview + +Yoresee Doc Backend provides: +- **Document Management**: Create, edit, version, and organize documents with attachment support +- **Knowledge Base**: Hierarchical knowledge base organization +- **User & Access Control**: User groups, organization structure, membership management, invitations +- **Real-time Collaboration**: Yjs snapshot persistence and conflict resolution +- **Full-text Search**: Elasticsearch integration for document search +- **Notifications**: Event-driven notification system via RabbitMQ + +## Architecture + +### High-Level Structure + +``` +┌─────────────────────────────────────────────────────────┐ +│ API Layer │ +│ Connect RPC handlers (HTTP/2 + gRPC-web) │ +│ - Auth interceptor (JWT) │ +│ - CORS support │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ Service Layer │ +│ Business logic with package-level singletons │ +│ - auth_service, document_service, etc. │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ Repository Layer │ +│ Data access with GORM (PostgreSQL) │ +│ - Constructed via repository.NewRepositories() │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ Infrastructure Layer │ +│ - PostgreSQL (primary data) │ +│ - Redis (cache, sessions, locks) │ +│ - MinIO (file storage) │ +│ - Elasticsearch (search index) │ +│ - RabbitMQ (message queue) │ +│ - Consul (service discovery/config) │ +└─────────────────────────────────────────────────────────┘ +``` + +### Project Layout + +``` +cmd/ +├── main.go # API server entry point +├── migrate/ # Database migration (GORM AutoMigrate) +├── db_init/ # Seed data (admin user, default groups, templates) +├── es_init/ # Elasticsearch index initialization +├── notification-worker/ # Notification consumer +├── search-sync-worker/ # Search index sync consumer +└── snapshot-worker/ # Yjs snapshot persistence consumer + +internal/ +├── bootstrap/ # Chain-style initializer (config → infra → services) +├── config/ # Viper TOML config loader +├── transport/ +│ ├── connectserver/ # HTTP mux, RPC handlers, auth interceptor +│ └── grpcserver/ # Per-service RPC implementations +├── service/ # Business logic (domain services) +│ ├── _service/ # Service implementations +│ ├── interface/ # Service interfaces +│ └── mq_service/ # Message queue abstraction +├── repository/ # Data access layer +│ ├── _repo/ # Repository implementations +│ └── init.go # Repository construction +├── model/ # GORM model definitions (16 models) +├── dto/ # Data transfer objects +├── mapper/ # Model ↔ DTO mappers +├── types/ # Domain types +└── status/ # Typed error codes + +pkg/ +├── storage/ # Infrastructure clients (DB, Redis, MinIO, ES, Consul) +├── mq/ # Message queue interface + RabbitMQ impl +├── cache/ # Cache utilities +├── lock/ # Distributed lock +├── key/ # Shared cache keys +├── errs/ # Shared errors +├── constant/ # Shared constants +└── gen/ # GENERATED protobuf stubs (gitignored) +``` + +## Prerequisites + +- **Go 1.24+** +- **PostgreSQL 15+** with `ltree` extension support +- **Redis 7+** +- **MinIO** (or S3-compatible object storage) +- **RabbitMQ 3+** +- **Consul 1.16+** +- **Elasticsearch 8+** (optional, for search functionality) + +All infrastructure services can be started via the project's Docker Compose setup. + +## Configuration + +### Config File + +Configuration is loaded from `config.toml` (gitignored), generated from `config.toml.tmpl` by `deploy/script/prepare.sh`. + +**Generation:** +```bash +# From repo root +bash deploy/script/prepare.sh +``` + +**Format:** TOML with environment variable substitution (`${ENV_VAR}`). + +**Environment variables:** Defined in `deploy/.env` (template: `deploy/.env.example`). + +**Access:** Via `config.GlobalConfig.*` singleton. + +### Key Configuration Sections + +```toml +[server] +grpc_port = 9090 # Native gRPC port +grpc_web_port = 8080 # gRPC-web port (browser clients) + +[database] +host = "localhost" +port = 5432 +user = "root" +password = "your_password" +name = "yoresee_doc_db" + +[redis] +host = "localhost" +port = 6379 +password = "your_redis_password" +db = 0 + +[consul] +enabled = true +address = "localhost:8500" +scheme = "http" +token = "yoresee_doc_root_token" +prefix = "yoresee_doc" + +[minio] +endpoint = "localhost:9000" +access_key = "minioadmin" +secret_key = "minioadmin" +bucket = "yoresee_doc" +use_ssl = false + +[elasticsearch] +enabled = true +addresses = ["http://localhost:9200"] +username = "elastic" +password = "your_password" +index_prefix = "yoresee_doc" + +[mq_config.rabbitmq] +url = "amqp://guest:guest@localhost:5672/" + +[backend] +system_name = "yoresee_doc" +internal_rpc_key = "yoresee_doc_internal_key" + +[backend.jwt] +secret = "yoresee_doc_jwt_secret_key" +expire = 86400 # 24 hours +refresh_expire = 604800 # 7 days + +[backend.security] +password_hash_cost = 12 +max_login_attempts = 5 +login_lock_duration = 30 # minutes +``` + +## Getting Started + +### 1. Start Infrastructure + +From the repository root: + +```bash +# Generate config files +bash deploy/script/configure.sh # Interactive setup +# OR +cp deploy/.env.example deploy/.env +bash deploy/script/prepare.sh # Non-interactive + +# Start all services via Docker Compose +bash deploy/script/start.sh dev up +``` + +This starts: +- PostgreSQL, Redis, Consul, MinIO, RabbitMQ, Elasticsearch +- Backend API server (with automatic migration + seeding) +- Background workers (snapshot, notification, search-sync) +- Frontend, collaboration services, nginx + +### 2. Run Backend Standalone (Optional) + +If infrastructure is already running externally: + +```bash +cd backend + +# Run migration + seeding +go run ./cmd/migrate +go run ./cmd/db_init +go run ./cmd/es_init + +# Start API server +go run ./cmd/main.go +``` + +### 3. Verify + +Health endpoints: +- `GET /health` — Liveness check +- `GET /readyz` — Readiness (checks DB + Redis) +- `GET /livez` — Liveness alias + +## API Structure + +### Connect RPC + +The backend exposes two HTTP listeners using Connect RPC (not raw gRPC): + +| Port | Purpose | Protocol | +|------|---------|----------| +| 9090 | Native gRPC | HTTP/2 | +| 8080 | gRPC-web | HTTP/1.1+ (browser clients) | + +Both listeners use h2c (HTTP/2 cleartext). + +### Services + +The API is organized into the following services: + +- **AuthService**: Login, register, profile management +- **DocumentService**: Document CRUD, versioning, attachments, templates +- **KnowledgeBaseService**: Knowledge base management +- **MembershipService**: User groups, org structure, memberships +- **InvitationService**: Invitation creation and management +- **NotificationService**: Notification CRUD, read status +- **CommentService**: Document comments +- **SettingService**: System settings +- **SystemService**: Health checks, system info + +### Authentication + +JWT-based authentication with the following unauthenticated endpoints: +- `AuthService.Login` +- `AuthService.Register` +- `SystemService.Health` +- `SystemService.SystemInfo` + +All other endpoints require a valid JWT in the `Authorization: Bearer ` header. + +## Background Workers + +### Snapshot Worker + +**Purpose:** Persist Yjs document snapshots to the database. + +**Queue:** Consumes from RabbitMQ topic for dirty document notifications. + +**Flow:** +1. Collab service marks document as dirty after edits +2. Snapshot worker receives notification +3. Fetches current Yjs state from collab service +4. Persists snapshot to `document_yjs_snapshots` table + +### Notification Worker + +**Purpose:** Process and deliver notifications. + +**Queue:** Consumes from RabbitMQ notification topics. + +### Search Sync Worker + +**Purpose:** Keep Elasticsearch index in sync with database. + +**Queue:** Consumes from RabbitMQ for document/KB changes. + +**Flow:** +1. Document/KB created/updated/deleted +2. Worker receives event +3. Updates Elasticsearch index accordingly + +## Database + +### Schema Management + +**Migration:** GORM `AutoMigrate` based on model struct definitions. + +**Location:** `cmd/migrate/migration.go` + +**Process:** +1. Creates PostgreSQL `ltree` extension (for hierarchical org structure) +2. Auto-migrates all 16 models +3. Creates custom indexes (unique constraints on recent items) +4. Applies manual migrations (e.g., dropping deprecated columns) + +**Models:** +- User +- Document, DocumentVersion, DocumentYjsSnapshot, DocumentComment +- KnowledgeBase +- Template +- Attachment +- Invitation, InvitationRecord +- Notification +- UserGroupMeta, MembershipRelation +- OrgNodeMeta +- RecentDocument, RecentKnowledgeBase, RecentTemplate + +### Seeding + +**Location:** `cmd/db_init/` + +**Process:** +1. Creates admin user (username: `admin`, password from config) +2. Creates default permissions +3. Creates default user groups +4. Creates default templates + +## Development + +### Code Structure Patterns + +**Service Layer:** +```go +// Package-level singleton +var AuthSvc *AuthService + +// Initialization in service.Init() +func Init(cfg *config.Config, repos *repository.Repositories) error { + auth_service.AuthSvc = auth_service.NewAuthService(repos) + // ... +} +``` + +**Repository Layer:** +```go +// Constructed via Repositories struct +type Repositories struct { + DB *gorm.DB + Redis *redis.Client + Document *document_repo.DocumentRepository + // ... +} + +func NewRepositories(db *gorm.DB, redis *redis.Client) *Repositories { + return &Repositories{ + Document: document_repo.NewDocumentRepository(db, redis), + // ... + } +} +``` + +**Error Handling:** +```go +// Typed errors with status codes +return status.GenErrWithCustomMsg( + status.StatusServiceInternalError, + "operation failed", +) +``` + +### Protobuf Codegen + +**Source:** `proto/yoresee_doc/v1/yoresee_doc.proto` + +**Generated Go code:** `pkg/gen/` (gitignored) + +**Regenerate:** +```bash +# From repo root +bash deploy/script/gen_proto.sh +``` + +**Targets:** +- `backend/pkg/gen` — Go stubs +- `collab-go/pkg/gen` — Go stubs +- `frontend/src/gen` — TypeScript ES modules +- `collab/src/gen` — Node gRPC stubs + +### Verification + +No linter or test suite configured. Verify changes with: + +```bash +go build ./... +go vet ./... +``` + +## Deployment + +### Docker Images + +| Dockerfile | Purpose | +|------------|---------| +| `Dockerfile` | Dev image (with Delve debugger) | +| `Dockerfile.prod` | Production API server | +| `Dockerfile.snapshot.prod` | Production snapshot worker | +| `Dockerfile.notification.prod` | Production notification worker | +| `Dockerfile.search-sync.prod` | Production search-sync worker | + +### Startup Sequence + +Container CMD for production: +```bash +./migrate.out && ./db_init.out && ./es_init.out && ./main.out +``` + +Workers are separate containers with their own entrypoints. + +### Health Checks + +Docker Compose uses `wget` to check `/health` endpoint: +```yaml +healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://backend:9090/health"] + interval: 5s + timeout: 3s + retries: 20 + start_period: 30s +``` + +## Infrastructure Ports + +| Service | Default Port | +|---------|--------------| +| Backend gRPC | 9090 | +| Backend gRPC-web | 8080 | +| Backend Debug (Delve) | 2345 | +| PostgreSQL | 5432 | +| Redis | 6379 | +| Consul | 8500 | +| MinIO API | 9000 | +| MinIO Console | 9001 | +| RabbitMQ AMQP | 5672 | +| RabbitMQ Management | 15672 | +| Elasticsearch | 9200 | + +## Key Dependencies + +- **Connect RPC** (`connectrpc.com/connect`) — Modern RPC framework +- **GORM** (`gorm.io/gorm`) — ORM for PostgreSQL +- **go-redis** (`github.com/redis/go-redis/v9`) — Redis client +- **MinIO Go** (`github.com/minio/minio-go/v7`) — S3-compatible storage +- **Viper** (`github.com/spf13/viper`) — Configuration management +- **Logrus** (`github.com/sirupsen/logrus`) — Structured logging +- **JWT** (`github.com/golang-jwt/jwt/v5`) — Authentication +- **amqp091-go** (`github.com/rabbitmq/amqp091-go`) — RabbitMQ client +- **improbable-eng/grpc-web** — gRPC-web proxy for browser clients +- **Snowflake** (`github.com/bwmarrin/snowflake`) — Distributed ID generation + +## Environment Variables + +All environment variables are defined in `deploy/.env` (see `deploy/.env.example` for template). + +Key variables: +- `POSTGRES_*` — Database connection +- `REDIS_*` — Redis connection +- `CONSUL_*` — Consul configuration +- `MINIO_*` — MinIO/S3 configuration +- `ELASTICSEARCH_*` — Elasticsearch configuration +- `RABBITMQ_*` — RabbitMQ configuration +- `BACKEND_*` — Backend service configuration +- `JWT_SECRET` — JWT signing secret + +## License + +[Your license here] + +## Contributing + +[Your contributing guidelines here] diff --git a/docs/README_zh.md b/docs/README_zh.md new file mode 100644 index 0000000..5f8b803 --- /dev/null +++ b/docs/README_zh.md @@ -0,0 +1,483 @@ +# Yoresee Doc 后端 + +Yoresee Doc 协作文档管理平台的后端服务,基于 Go 和 Connect RPC 构建。 + +## 概述 + +Yoresee Doc 后端提供: +- **文档管理**:创建、编辑、版本控制、组织文档,支持附件 +- **知识库**:层级化知识库组织 +- **用户与权限控制**:用户组、组织结构、成员管理、邀请 +- **实时协作**:Yjs 快照持久化和冲突解决 +- **全文搜索**:Elasticsearch 集成实现文档搜索 +- **通知系统**:基于 RabbitMQ 的事件驱动通知 + +## 架构 + +### 高层结构 + +``` +┌─────────────────────────────────────────────────────────┐ +│ API 层 │ +│ Connect RPC 处理器 (HTTP/2 + gRPC-web) │ +│ - 认证拦截器 (JWT) │ +│ - CORS 支持 │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ 服务层 │ +│ 业务逻辑,使用包级单例 │ +│ - auth_service, document_service 等 │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ 仓储层 │ +│ 使用 GORM (PostgreSQL) 的数据访问 │ +│ - 通过 repository.NewRepositories() 构造 │ +└─────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────┐ +│ 基础设施层 │ +│ - PostgreSQL (主数据存储) │ +│ - Redis (缓存、会话、锁) │ +│ - MinIO (文件存储) │ +│ - Elasticsearch (搜索索引) │ +│ - RabbitMQ (消息队列) │ +│ - Consul (服务发现/配置) │ +└─────────────────────────────────────────────────────────┘ +``` + +### 项目结构 + +``` +cmd/ +├── main.go # API 服务器入口 +├── migrate/ # 数据库迁移 (GORM AutoMigrate) +├── db_init/ # 种子数据 (管理员用户、默认分组、模板) +├── es_init/ # Elasticsearch 索引初始化 +├── notification-worker/ # 通知消费者 +├── search-sync-worker/ # 搜索索引同步消费者 +└── snapshot-worker/ # Yjs 快照持久化消费者 + +internal/ +├── bootstrap/ # 链式初始化器 (配置 → 基础设施 → 服务) +├── config/ # Viper TOML 配置加载器 +├── transport/ +│ ├── connectserver/ # HTTP 多路复用、RPC 处理器、认证拦截器 +│ └── grpcserver/ # 各服务的 RPC 实现 +├── service/ # 业务逻辑 (领域服务) +│ ├── _service/ # 服务实现 +│ ├── interface/ # 服务接口 +│ └── mq_service/ # 消息队列抽象 +├── repository/ # 数据访问层 +│ ├── _repo/ # 仓储实现 +│ └── init.go # 仓储构造 +├── model/ # GORM 模型定义 (16 个模型) +├── dto/ # 数据传输对象 +├── mapper/ # 模型 ↔ DTO 映射器 +├── types/ # 领域类型 +└── status/ # 类型化错误码 + +pkg/ +├── storage/ # 基础设施客户端 (DB、Redis、MinIO、ES、Consul) +├── mq/ # 消息队列接口 + RabbitMQ 实现 +├── cache/ # 缓存工具 +├── lock/ # 分布式锁 +├── key/ # 共享缓存键 +├── errs/ # 共享错误 +├── constant/ # 共享常量 +└── gen/ # 生成的 protobuf 代码 (gitignored) +``` + +## 前置要求 + +- **Go 1.24+** +- **PostgreSQL 15+** 支持 `ltree` 扩展 +- **Redis 7+** +- **MinIO** (或 S3 兼容对象存储) +- **RabbitMQ 3+** +- **Consul 1.16+** +- **Elasticsearch 8+** (可选,用于搜索功能) + +所有基础设施服务可通过项目的 Docker Compose 配置启动。 + +## 配置 + +### 配置文件 + +配置从 `config.toml` (gitignored) 加载,由 `deploy/script/prepare.sh` 从 `config.toml.tmpl` 生成。 + +**生成:** +```bash +# 在仓库根目录 +bash deploy/script/prepare.sh +``` + +**格式:** TOML,支持环境变量替换 (`${ENV_VAR}`)。 + +**环境变量:** 在 `deploy/.env` 中定义 (模板:`deploy/.env.example`)。 + +**访问方式:** 通过 `config.GlobalConfig.*` 单例。 + +### 关键配置部分 + +```toml +[server] +grpc_port = 9090 # 原生 gRPC 端口 +grpc_web_port = 8080 # gRPC-web 端口 (浏览器客户端) + +[database] +host = "localhost" +port = 5432 +user = "root" +password = "your_password" +name = "yoresee_doc_db" + +[redis] +host = "localhost" +port = 6379 +password = "your_redis_password" +db = 0 + +[consul] +enabled = true +address = "localhost:8500" +scheme = "http" +token = "yoresee_doc_root_token" +prefix = "yoresee_doc" + +[minio] +endpoint = "localhost:9000" +access_key = "minioadmin" +secret_key = "minioadmin" +bucket = "yoresee_doc" +use_ssl = false + +[elasticsearch] +enabled = true +addresses = ["http://localhost:9200"] +username = "elastic" +password = "your_password" +index_prefix = "yoresee_doc" + +[mq_config.rabbitmq] +url = "amqp://guest:guest@localhost:5672/" + +[backend] +system_name = "yoresee_doc" +internal_rpc_key = "yoresee_doc_internal_key" + +[backend.jwt] +secret = "yoresee_doc_jwt_secret_key" +expire = 86400 # 24 小时 +refresh_expire = 604800 # 7 天 + +[backend.security] +password_hash_cost = 12 +max_login_attempts = 5 +login_lock_duration = 30 # 分钟 +``` + +## 快速开始 + +### 1. 启动基础设施 + +在仓库根目录: + +```bash +# 生成配置文件 +bash deploy/script/configure.sh # 交互式设置 +# 或 +cp deploy/.env.example deploy/.env +bash deploy/script/prepare.sh # 非交互式 + +# 通过 Docker Compose 启动所有服务 +bash deploy/script/start.sh dev up +``` + +这将启动: +- PostgreSQL、Redis、Consul、MinIO、RabbitMQ、Elasticsearch +- 后端 API 服务器 (自动迁移 + 种子数据) +- 后台工作器 (快照、通知、搜索同步) +- 前端、协作服务、nginx + +### 2. 独立运行后端 (可选) + +如果基础设施已在外部运行: + +```bash +cd backend + +# 运行迁移 + 种子数据 +go run ./cmd/migrate +go run ./cmd/db_init +go run ./cmd/es_init + +# 启动 API 服务器 +go run ./cmd/main.go +``` + +### 3. 验证 + +健康检查端点: +- `GET /health` — 存活检查 +- `GET /readyz` — 就绪检查 (检查 DB + Redis) +- `GET /livez` — 存活检查别名 + +## API 结构 + +### Connect RPC + +后端使用 Connect RPC (非原生 gRPC) 暴露两个 HTTP 监听器: + +| 端口 | 用途 | 协议 | +|------|------|------| +| 9090 | 原生 gRPC | HTTP/2 | +| 8080 | gRPC-web | HTTP/1.1+ (浏览器客户端) | + +两个监听器都使用 h2c (HTTP/2 明文)。 + +### 服务 + +API 组织为以下服务: + +- **AuthService**:登录、注册、个人资料管理 +- **DocumentService**:文档 CRUD、版本控制、附件、模板 +- **KnowledgeBaseService**:知识库管理 +- **MembershipService**:用户组、组织结构、成员关系 +- **InvitationService**:邀请创建和管理 +- **NotificationService**:通知 CRUD、已读状态 +- **CommentService**:文档评论 +- **SettingService**:系统设置 +- **SystemService**:健康检查、系统信息 + +### 认证 + +基于 JWT 的认证,以下端点无需认证: +- `AuthService.Login` +- `AuthService.Register` +- `SystemService.Health` +- `SystemService.SystemInfo` + +所有其他端点需要在 `Authorization: Bearer ` 头中提供有效的 JWT。 + +## 后台工作器 + +### 快照工作器 + +**用途:** 将 Yjs 文档快照持久化到数据库。 + +**队列:** 消费 RabbitMQ 主题中的脏文档通知。 + +**流程:** +1. 协作服务在编辑后将文档标记为脏 +2. 快照工作器接收通知 +3. 从协作服务获取当前 Yjs 状态 +4. 将快照持久化到 `document_yjs_snapshots` 表 + +### 通知工作器 + +**用途:** 处理和投递通知。 + +**队列:** 消费 RabbitMQ 通知主题。 + +### 搜索同步工作器 + +**用途:** 保持 Elasticsearch 索引与数据库同步。 + +**队列:** 消费 RabbitMQ 中的文档/知识库变更。 + +**流程:** +1. 文档/知识库被创建/更新/删除 +2. 工作器接收事件 +3. 相应更新 Elasticsearch 索引 + +## 数据库 + +### 模式管理 + +**迁移:** 基于模型结构体定义的 GORM `AutoMigrate`。 + +**位置:** `cmd/migrate/migration.go` + +**流程:** +1. 创建 PostgreSQL `ltree` 扩展 (用于层级组织结构) +2. 自动迁移所有 16 个模型 +3. 创建自定义索引 (最近访问项的唯一约束) +4. 应用手动迁移 (例如,删除已弃用的列) + +**模型:** +- User (用户) +- Document, DocumentVersion, DocumentYjsSnapshot, DocumentComment (文档相关) +- KnowledgeBase (知识库) +- Template (模板) +- Attachment (附件) +- Invitation, InvitationRecord (邀请相关) +- Notification (通知) +- UserGroupMeta, MembershipRelation (用户组和成员关系) +- OrgNodeMeta (组织节点) +- RecentDocument, RecentKnowledgeBase, RecentTemplate (最近访问) + +### 种子数据 + +**位置:** `cmd/db_init/` + +**流程:** +1. 创建管理员用户 (用户名:`admin`,密码来自配置) +2. 创建默认权限 +3. 创建默认用户组 +4. 创建默认模板 + +## 开发 + +### 代码结构模式 + +**服务层:** +```go +// 包级单例 +var AuthSvc *AuthService + +// 在 service.Init() 中初始化 +func Init(cfg *config.Config, repos *repository.Repositories) error { + auth_service.AuthSvc = auth_service.NewAuthService(repos) + // ... +} +``` + +**仓储层:** +```go +// 通过 Repositories 结构体构造 +type Repositories struct { + DB *gorm.DB + Redis *redis.Client + Document *document_repo.DocumentRepository + // ... +} + +func NewRepositories(db *gorm.DB, redis *redis.Client) *Repositories { + return &Repositories{ + Document: document_repo.NewDocumentRepository(db, redis), + // ... + } +} +``` + +**错误处理:** +```go +// 带状态码的类型化错误 +return status.GenErrWithCustomMsg( + status.StatusServiceInternalError, + "operation failed", +) +``` + +### Protobuf 代码生成 + +**源文件:** `proto/yoresee_doc/v1/yoresee_doc.proto` + +**生成的 Go 代码:** `pkg/gen/` (gitignored) + +**重新生成:** +```bash +# 在仓库根目录 +bash deploy/script/gen_proto.sh +``` + +**目标:** +- `backend/pkg/gen` — Go 代码 +- `collab-go/pkg/gen` — Go 代码 +- `frontend/src/gen` — TypeScript ES 模块 +- `collab/src/gen` — Node gRPC 代码 + +### 代码验证 + +未配置 linter 或测试套件。使用以下命令验证更改: + +```bash +go build ./... +go vet ./... +``` + +## 部署 + +### Docker 镜像 + +| Dockerfile | 用途 | +|------------|------| +| `Dockerfile` | 开发镜像 (含 Delve 调试器) | +| `Dockerfile.prod` | 生产 API 服务器 | +| `Dockerfile.snapshot.prod` | 生产快照工作器 | +| `Dockerfile.notification.prod` | 生产通知工作器 | +| `Dockerfile.search-sync.prod` | 生产搜索同步工作器 | + +### 启动顺序 + +生产环境容器 CMD: +```bash +./migrate.out && ./db_init.out && ./es_init.out && ./main.out +``` + +工作器是独立的容器,有自己的入口点。 + +### 健康检查 + +Docker Compose 使用 `wget` 检查 `/health` 端点: +```yaml +healthcheck: + test: ["CMD", "wget", "--spider", "-q", "http://backend:9090/health"] + interval: 5s + timeout: 3s + retries: 20 + start_period: 30s +``` + +## 基础设施端口 + +| 服务 | 默认端口 | +|------|----------| +| 后端 gRPC | 9090 | +| 后端 gRPC-web | 8080 | +| 后端调试 (Delve) | 2345 | +| PostgreSQL | 5432 | +| Redis | 6379 | +| Consul | 8500 | +| MinIO API | 9000 | +| MinIO 控制台 | 9001 | +| RabbitMQ AMQP | 5672 | +| RabbitMQ 管理界面 | 15672 | +| Elasticsearch | 9200 | + +## 关键依赖 + +- **Connect RPC** (`connectrpc.com/connect`) — 现代 RPC 框架 +- **GORM** (`gorm.io/gorm`) — PostgreSQL ORM +- **go-redis** (`github.com/redis/go-redis/v9`) — Redis 客户端 +- **MinIO Go** (`github.com/minio/minio-go/v7`) — S3 兼容存储 +- **Viper** (`github.com/spf13/viper`) — 配置管理 +- **Logrus** (`github.com/sirupsen/logrus`) — 结构化日志 +- **JWT** (`github.com/golang-jwt/jwt/v5`) — 认证 +- **amqp091-go** (`github.com/rabbitmq/amqp091-go`) — RabbitMQ 客户端 +- **improbable-eng/grpc-web** — 浏览器客户端的 gRPC-web 代理 +- **Snowflake** (`github.com/bwmarrin/snowflake`) — 分布式 ID 生成 + +## 环境变量 + +所有环境变量在 `deploy/.env` 中定义 (参见 `deploy/.env.example` 获取模板)。 + +关键变量: +- `POSTGRES_*` — 数据库连接 +- `REDIS_*` — Redis 连接 +- `CONSUL_*` — Consul 配置 +- `MINIO_*` — MinIO/S3 配置 +- `ELASTICSEARCH_*` — Elasticsearch 配置 +- `RABBITMQ_*` — RabbitMQ 配置 +- `BACKEND_*` — 后端服务配置 +- `JWT_SECRET` — JWT 签名密钥 + +## 许可证 + +[在此填写您的许可证] + +## 贡献 + +[在此填写您的贡献指南]