diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..961715b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig is awesome: https://EditorConfig.org +# 跨编辑器 / IDE 的代码格式配置文件 + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{js,jsx,ts,tsx,vue,json,css,scss,less,html,md,yml,yaml}] +indent_size = 2 + +[*.{py}] +indent_size = 4 + +[Makefile] +indent_style = tab diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..1cc07d5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,53 @@ +name: Bug Report (问题报告) +description: 提交运行错误、异常行为或缺陷 +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + 感谢你帮助改进本项目!提交 Bug 前请先在已有的 Issue 中搜索是否已有相同问题。 + - type: textarea + id: description + attributes: + label: 问题描述 (Description) + description: 请清晰、简要地描述遇到的问题或异常行为。 + placeholder: 在执行 ... 时出现了 ... + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: 复现步骤 (Steps to Reproduce) + description: 请提供逐步复现该问题的详细步骤。 + placeholder: | + 1. 运行 '...' + 2. 点击 '...' + 3. 查看错误信息 + validations: + required: true + - type: textarea + id: expected + attributes: + label: 预期行为 (Expected Behavior) + description: 描述你期望发生的结果。 + validations: + required: false + - type: textarea + id: logs + attributes: + label: 错误日志与堆栈 (Logs / Traceback) + description: 请粘贴相关终端输出、Docker 容器日志或浏览器控制台报错。 + render: shell + validations: + required: false + - type: textarea + id: environment + attributes: + label: 运行环境 (Environment) + description: 系统与依赖环境信息。 + value: | + - OS: [e.g. Ubuntu 22.04 / macOS 14 / Windows 11] + - Docker Version: [e.g. 24.0.5] + - Browser / Node / Python Version: + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..0086358 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..d4a0ff4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,30 @@ +name: Feature Request (功能需求) +description: 提出新的功能建议或改进想法 +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + 我们欢迎任何有助于提升产品体验或拓展生态能力的建议! + - type: textarea + id: problem + attributes: + label: 目标场景与痛点 (Problem / Motivation) + description: 该功能旨在解决什么问题?或在什么场景下会用到? + placeholder: 我希望在 ... 时能够 ...,因为目前 ... + validations: + required: true + - type: textarea + id: solution + attributes: + label: 建议的方案 (Proposed Solution) + description: 请清晰描述你希望的功能实现方式或用户体验。 + validations: + required: true + - type: textarea + id: alternatives + attributes: + label: 考虑过的替代方案 (Alternatives Considered) + description: 是否考虑过其他临时绕过方式或现有工具? + validations: + required: false diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..7f1e0a9 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## 变更说明 (Description) + + +## 关联 Issue (Related Issue) + + +## 变更类型 (Type of Change) +- [ ] 🐛 Bug 修复 (Bug fix) +- [ ] ✨ 新功能 (New feature) +- [ ] 📝 文档更新 (Documentation update) +- [ ] 🎨 代码风格/重构 (Refactoring / Code style) +- [ ] ⚡ 性能优化 (Performance improvement) +- [ ] 🔧 构建/配置/CI (Build / CI / Chores) + +## 验证与测试 (Verification) + +- [ ] 本地测试通过 (测试套件全绿) +- [ ] 代码符合仓库规范(通过 Linter 检查) +- [ ] 文档已同步更新(若涉及接口或配置变动) + +## 其他说明 (Notes) + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5f40535 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# 贡献指南 (Contributing Guide) + +感谢你关注并愿意为本项目贡献力量!本项目是 **\*Flow 生态** 的一部分,致力于提供轻量、本地优先与 Agent 原生的研发与生产力工作流。 + +## 提交前准备 + +1. **查阅 Issue**:在提交重大功能或重构前,请先创建 Issue 进行方案讨论。 +2. **规范阅读**:请阅读 [AGENTS.md](AGENTS.md) 以及 `docs/` 目录下的相关规范与架构设计文档。 + +## 研发工作流 + +1. **Fork & Clone**:Fork 本仓库并 Clone 到本地。 +2. **创建特性分支**: + ```bash + git checkout -b feature/your-feature-name + # 或 + git checkout -b fix/your-bug-fix + ``` +3. **环境与依赖**: + - 请根据项目 README 配置本地依赖与 `.env` 文件。 + - 绝不提交真实的 Secret、API Key 或生产数据。 +4. **代码风格与检查**: + - 提交前请确保运行门禁检查命令通过。 + - Python 代码遵循 Ruff 规则与 PEP 8 标准。 + - TypeScript/前端代码遵循 ESLint 与 Prettier 格式。 +5. **提交规范 (Commit Convention)**: + 提交信息推荐遵循 Conventional Commits: + - `feat: 新增功能` + - `fix: 修复 Bug` + - `docs: 更新文档` + - `style: 格式与代码风格变动` + - `refactor: 代码重构` + - `test: 增加或修改测试` + - `chore: 构建或辅助工具变动` + +## Pull Request 流程 + +1. 确保你的分支与 upstream `main` 保持最新。 +2. 填写完整的 PR 模板,并关联相关 Issue。 +3. 等待 CI 自动化流水线验证通过。 diff --git a/LICENSE b/LICENSE index 8237d2d..e8f597a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2026 mcocdaa - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2026 mcocdaa + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 59cdb77..fbdb35e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,14 @@ # MeetFlow +> 轻量级多人共享会议档案、结构化行动项追踪与团队知识沉淀系统。 + +[![Family: *Flow](https://img.shields.io/badge/family-*Flow-8A2BE2.svg)](https://github.com/mcocdaa) [![CI](https://github.com/mcocdaa/MeetFlow/actions/workflows/ci.yml/badge.svg)](https://github.com/mcocdaa/MeetFlow/actions/workflows/ci.yml) +[![Release](https://img.shields.io/github/v/release/mcocdaa/MeetFlow?display_name=tag&sort=semver)](https://github.com/mcocdaa/MeetFlow/releases) [![Container image](https://img.shields.io/badge/image-ghcr.io%2Fmcocdaa%2Fmeetflow-0b6a58)](https://github.com/mcocdaa/MeetFlow/pkgs/container/meetflow) -[![License](https://img.shields.io/github/license/mcocdaa/MeetFlow)](LICENSE) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) +[![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/) +[![Docker](https://img.shields.io/badge/docker-ready-blue.svg)](compose.yaml) MeetFlow 是一个轻量级多人共享会议档案工具。一次会议可以保存 Markdown 原始记录、关键结论、结构化行动项、后续补充、图片与小文件。所有成员使用同一个共享工作区;管理员负责账号审批和插件配置。 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..a9ed6a8 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,17 @@ +# 安全策略 (Security Policy) + +## 漏洞报告 (Reporting a Vulnerability) + +如果您在本项目中发现了安全漏洞或潜在的风险点,请**不要**直接公开创建 Issue。 + +请通过以下安全渠道联系项目维护者: +- **Email**: 通过维护者 GitHub 个人主页公开渠道或私信联系 (`mcocdaa`) +- **GitHub Private Vulnerability Reporting**: 在仓库的 **Security** -> **Advisories** 中提交私密漏洞报告 + +### 报告时请提供以下信息: +1. 漏洞类型及严重程度评估 +2. 受影响的组件、文件或 API 端点 +3. 详细的复现步骤或最小可复现示例 (PoC) +4. 任何可能的修复建议或缓解措施 + +维护团队将在 48 小时内确认并评估漏洞,并在发布修复版本后妥善致谢。 diff --git a/docs/rules/api-spec.md b/docs/rules/api-spec.md new file mode 100644 index 0000000..3e41b8c --- /dev/null +++ b/docs/rules/api-spec.md @@ -0,0 +1,212 @@ +--- +title: API规范 +description: 通用RESTful API架构规范 +keywords: [api, rest, version-control, router-loader] +version: "2.0" +--- + +# API 规范 + +本规范适用于任何软件项目的 RESTful API 架构设计。 + +### 特性 + +- 路由自动加载:扫描目录自动挂载 +- 版本控制:动态加载指定版本 +- 统一前缀:`/api` + +--- + +## 目录结构 + +``` +backend/ +├── api/ +│ ├── __init__.py # 路由总入口 +│ └── v1/ # API 版本 +│ ├── __init__.py # 版本路由汇总 +│ ├── A.py # 资源模块 +│ └── C/ # 子命名空间 +│ ├── __init__.py +│ └── C1.py +├── core/ +│ └── router_loader.py # 路由自动加载器 +``` + +--- + +## 核心代码 + +### 路由总入口 `api/__init__.py` + +```python +# @file backend/api/__init__.py +# @brief API 路由总入口 - 支持版本控制 + +import importlib +from fastapi import FastAPI +from XXXX.settings import API_VERSION + +def register_routers(app: FastAPI): + version_package_name = f"{__name__}.{API_VERSION}" + + try: + version_package = importlib.import_module(version_package_name) + except ModuleNotFoundError: + raise RuntimeError(f"API 版本模块不存在: {version_package_name}") + + if hasattr(version_package, "router"): + app.include_router( + version_package.router, + prefix="/api", + tags=[API_VERSION.upper()] + ) +``` + +### 模块路由汇总 `api/v1/__init__.py` 或 `api/v1/C/__init__.py` + +```python +# @file backend/api/v1/__init__.py +# @brief API v1 模块路由汇总 + +from fastapi import APIRouter +from pathlib import Path +from core.router_loader import include_routers_from_directory + +router = APIRouter() + +include_routers_from_directory( + parent_router=router, + package_name=__package__, + directory_path=Path(__file__).parent, + auto_tag=False, + auto_prefix=False, + skip_modules=[], +) +``` + +### 路由自动加载器 `core/router_loader.py` + +```python +# @file backend/core/router_loader.py +# @brief 自动路由加载器 + +from fastapi import APIRouter +import importlib +from pathlib import Path +from typing import List, Optional + +def include_routers_from_directory( + parent_router: APIRouter, + package_name: str, + directory_path: Path, + *, + skip_modules: Optional[List[str]] = None, + auto_tag: bool = False, + auto_prefix: bool = False +) -> None: + if skip_modules is None: + skip_modules = [] + + base_name = package_name.split(".")[-1] + + for path in directory_path.iterdir(): + if path.name == "__init__.py": + continue + + module_name = None + + if path.is_file() and path.suffix == ".py": + module_name = path.stem + elif path.is_dir() and (path / "__init__.py").exists(): + module_name = path.name + + if not module_name or module_name in skip_modules: + continue + + try: + module = importlib.import_module(f".{module_name}", package=package_name) + + if hasattr(module, "router"): + sub_router = getattr(module, "router") + + kwargs = {"prefix": f"/{base_name}"} + if auto_tag: + kwargs["tags"] = [module_name] + if auto_prefix: + kwargs["prefix"] += f"/{module_name}" + + parent_router.include_router(sub_router, **kwargs) + + except Exception as e: + print(f"[RouterLoader] 挂载失败 {module_name}: {str(e)}") +``` + +--- + +## 加载流程 + +``` +app = FastAPI() + │ + ▼ +register_routers(app) + │ + ▼ +动态导入 api.v1 + │ + ▼ +include_routers_from_directory() 扫描目录 + │ + ├── A.py → /v1/A + └── C/ → /v1/C + └── C1.py → /v1/C/C1 +``` + +--- + +## 子路由模块规范 + +每个路由模块需定义 `router` 对象: + +```python +# @file backend/api/v1/A.py +from fastapi import APIRouter + +router = APIRouter() + +@router.get("/A") +async def get_list(): + return [] +``` + +--- + +## 参数说明 + +| 参数 | 说明 | +|------|------| +| skip_modules | 跳过加载的模块名列表 | +| auto_tag | 为路由添加模块名作为标签 | +| auto_prefix | 自动追加模块名前缀 | + +| auto_tag | auto_prefix | 路由前缀 | +|----------|-------------|---------| +| False | False | /v1 | +| True | False | /v1 (带标签) | +| True | True | /v1/C (带标签) | + +--- + +## 复用 + +1. 复制核心文件: + - `api/__init__.py` + - `api/v1/__init__.py` + - `core/router_loader.py` + +2. 目录结构保持一致 + +3. 配置 `API_VERSION` + +4. 应用入口调用 `register_routers(app)` diff --git a/docs/rules/code.md b/docs/rules/code.md new file mode 100644 index 0000000..3716db2 --- /dev/null +++ b/docs/rules/code.md @@ -0,0 +1,267 @@ +--- +title: 代码规范 +description: 通用代码编写规范与最佳实践 +keywords: [代码规范, code, 最佳实践] +version: "2.0" +--- + +# 代码规范 + +本规范适用于任何软件项目的代码编写。 + +## 目录 +- [1. 导入规范](#1-导入规范) +- [2. 命名规范](#2-命名规范) +- [3. 类型注解](#3-类型注解) +- [4. 文档字符串](#4-文档字符串) +- [5. 异常处理](#5-异常处理) +- [6. 常量定义](#6-常量定义) +- [7. 日志规范](#7-日志规范) +- [8. 文件组织](#8-文件组织) +- [9. 代码审查清单](#9-代码审查清单) + +--- + +## 1. 导入规范 + +### 1.1 移除未使用的导入 +**✗ 错误示例:** +```python +import os +import sys +import json # 未使用 +import asyncio # 未使用 +``` + +**✓ 正确示例:** +```python +import os +import sys +``` + +### 1.2 导入顺序 +按以下顺序分组导入: +1. 标准库 +2. 第三方库 +3. 本地模块 + +每组之间空一行。 + +**✓ 正确示例:** +```python +import os +import sys +from typing import Dict, List + +import yaml +from fastapi import FastAPI + +from core import setting_manager +from managers import session_manager +``` + +--- + +## 2. 命名规范 + +### 2.1 常量命名 +使用全大写下划线分隔。 + +**✗ 错误示例:** +```python +secret_bytes = 24 +max_wait = 50 +``` + +**✓ 正确示例:** +```python +SECRET_TOKEN_BYTES = 24 +REFRESH_WAIT_MAX_ITERATIONS = 50 +DEFAULT_LOG_LEVEL = "INFO" +``` + +### 2.2 枚举类型 +对于状态值、类型等,使用 `Enum`。 + +**✗ 错误示例:** +```python +if status == "raw": + ... +elif status == "approved": + ... +``` + +**✓ 正确示例:** +```python +from enum import Enum + +class SessionStatus(Enum): + RAW = "raw" + CURATED = "curated" + APPROVED = "approved" + +if status == SessionStatus.RAW: + ... +``` + +--- + +## 3. 类型注解 + +### 3.1 公共方法必须有类型注解 +所有公共方法的参数和返回值都必须添加类型注解。 + +**✗ 错误示例:** +```python +def get_session(self, session_id): + ... +``` + +**✓ 正确示例:** +```python +def get_session(self, session_id: str) -> Optional[Dict[str, Any]]: + ... +``` + +--- + +## 4. 文档字符串 + +### 4.1 Google 风格文档字符串 +所有公共方法必须有文档字符串,使用 Google 风格。 + +**✓ 正确示例:** +```python +def get_session(self, session_id: str) -> Optional[Dict[str, Any]]: + """获取单个会话 + + Args: + session_id: 会话ID + + Returns: + 会话字典,如果不存在返回 None + """ + ... +``` + +--- + +## 5. 异常处理 + +### 5.1 避免捕获所有异常 +尽可能捕获具体的异常类型。 + +**✗ 错误示例:** +```python +try: + data = json.load(f) +except Exception: + logger.error("加载失败") +``` + +**✓ 正确示例:** +```python +try: + data = json.load(f) +except json.JSONDecodeError as e: + logger.error(f"JSON 解析失败: {e}") +except IOError as e: + logger.error(f"文件读取失败: {e}") +``` + +### 5.2 记录异常堆栈 +使用 `exc_info=True` 记录完整堆栈。 + +**✓ 正确示例:** +```python +try: + ... +except Exception as e: + logger.error(f"操作失败: {e}", exc_info=True) +``` + +--- + +## 6. 常量定义 + +### 6.1 避免魔法数字 +所有字面量数值都应该定义为常量。 + +**✗ 错误示例:** +```python +token = secrets.token_bytes(24) +for _ in range(50): + ... +``` + +**✓ 正确示例:** +```python +SECRET_TOKEN_BYTES = 24 +REFRESH_WAIT_MAX_ITERATIONS = 50 + +token = secrets.token_bytes(SECRET_TOKEN_BYTES) +for _ in range(REFRESH_WAIT_MAX_ITERATIONS): + ... +``` + +--- + +## 7. 日志规范 + +### 7.1 统一使用 logging +禁止使用 `print`,统一使用 `logging` 模块。 + +**✗ 错误示例:** +```python +print("[Route] 已注册 API") +``` + +**✓ 正确示例:** +```python +logger.info("[Route] 已注册 API") +``` + +### 7.2 日志级别 +- `DEBUG`: 调试信息 +- `INFO`: 一般信息 +- `WARNING`: 警告信息 +- `ERROR`: 错误信息 + +--- + +## 8. 文件组织 + +### 8.1 文件大小 +单个文件建议不超过 400 行。超过时考虑拆分为多个模块。 + +| 建议 | 操作 | +|------|------| +| < 400 行 | 保持 | +| 400-500 行 | 考虑拆分 | +| > 500 行 | 必须拆分 | + +### 8.2 删除死代码 +删除未使用的方法、变量和类。 + +**✗ 错误示例:** +```python +def _unused_method(self): + """从未被调用的方法""" + ... +``` + +--- + +## 9. 代码审查清单 + +提交代码前,请检查以下项目: + +- [ ] 移除所有未使用的导入 +- [ ] 移除所有未使用的变量和方法 +- [ ] 所有魔法数字已定义为常量 +- [ ] 使用 logging 而不是 print +- [ ] 公共方法有类型注解 +- [ ] 公共方法有文档字符串 +- [ ] 异常处理尽可能具体 +- [ ] 文件不超过 500 行 +- [ ] 运行测试通过 diff --git a/docs/rules/docker.md b/docs/rules/docker.md new file mode 100644 index 0000000..b97b4ef --- /dev/null +++ b/docs/rules/docker.md @@ -0,0 +1,126 @@ +--- +title: Docker 部署规范 +description: 通用Docker容器化部署规范 +keywords: [docker, compose, 部署规范] +version: "3.0" +--- + +# Docker 部署规范 + +本规范适用于任何软件项目的 Docker 容器化部署。 + +## 1. 默认形态:单镜像全栈 + +前后端项目默认打成**一个镜像**:多阶段构建前端静态文件,COPY 进后端镜像,由后端在**同一端口**提供页面与 API。 + +优点:一条 `docker run` 即可部署,无跨容器网络与 CORS 配置;多服务(DB/缓存/MQ)场景才需要拆分。 + +### 1.1 目录结构 + +``` +project-root/ +├── docker-compose.yml # 唯一入口(单服务,同时声明 image 与 build) +├── .env.example # 配置模板(提交到 Git) +├── .dockerignore +├── backend/ +│ └── Dockerfile # 多阶段:frontend-builder + 运行镜像 +└── scripts/ + ├── start.sh # 统一启动入口 + └── stop.sh +``` + +**规则:** + +- 单服务不预先做 compose 分层;出现第二个服务时再拆分或引入 `compose.override.yml` +- 不再为"仅前端"维护独立镜像:页面随全栈镜像发布,前端开发走本地 dev server + +### 1.2 多阶段 Dockerfile 示例 + +```dockerfile +# 构建前端静态文件 +FROM node:22-alpine AS frontend-builder +WORKDIR /build/frontend +COPY frontend/package.json frontend/package-lock.json* ./ +RUN npm ci +COPY frontend/ ./ +RUN npm run build:web + +# 运行镜像 +FROM python:3.12-slim +ENV SERVE_STATIC_FILES=true STATIC_FILES_DIR=/app/static +WORKDIR /app/backend +COPY backend/pyproject.toml backend/poetry.lock ./ +RUN pip install --no-cache-dir poetry==2.3.3 \ + && poetry config virtualenvs.create false \ + && poetry install --only main --no-interaction --no-ansi --no-root +COPY backend/ ./ +COPY --from=frontend-builder /build/frontend/dist /app/static +HEALTHCHECK CMD curl -fsS http://localhost:3000/health || exit 1 +CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port 3000"] +``` + +### 1.3 Compose 示例 + +```yaml +services: + app: + image: ghcr.io//:latest + build: + context: . + dockerfile: backend/Dockerfile + restart: unless-stopped + ports: + - "${BACKEND_EXTERNAL_PORT:-3001}:3000" + environment: + - LOG_LEVEL=${LOG_LEVEL:-INFO} + - API_KEY=${API_KEY:-} + healthcheck: + test: ["CMD", "curl", "-fsS", "http://localhost:3000/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s +``` + +## 2. 配置管理 + +- `.env.example` 提交到 Git,`.env` 不入库;`docker compose` 会自动读取 `.env` 做变量替换 +- 端口、日志级别、开关等非敏感项走 `.env` +- API Key / Token / Cookie 默认同样通过 `.env` 注入(文件已 gitignore);需要更强隔离时再使用 Docker secrets 或外部密钥系统 +- 应用统一从环境变量读取配置,可兼容 `env:VAR` 形式的引用解析 +- `.env.example` 保持最小集:只保留真实被读取的键 + +## 3. 运行约定 + +- 镜像内部端口固定(如 3000),宿主机端口由 `*_EXTERNAL_PORT` 控制 +- 必须定义 `HEALTHCHECK`,并与 compose 的 healthcheck 保持一致 +- 基础镜像使用具体版本标签(禁止 `FROM ...:latest`) +- apt 安装使用 `--no-install-recommends` 并清理 `/var/lib/apt/lists/*` +- 应用需要写挂载目录时再引入非 root 用户,并同步处理目录权限 + +## 4. 启动脚本 + +所有启动操作统一走 `scripts/`,README 中的命令必须与脚本行为一致: + +| 命令 | 说明 | +|------|------| +| `./scripts/start.sh` | 构建并启动 Docker 全栈(默认) | +| `./scripts/start.sh local [all\|backend\|frontend]` | 本地开发进程(不经 Docker) | +| `./scripts/stop.sh` | 停止 Docker 全栈 | + +脚本负责:首次运行时从 `.env.example` 生成 `.env`、加载变量、启动服务并打印访问地址。 + +## 5. 发布(CD) + +- 打 `v*` tag 时由 CI 构建并推送镜像到 GHCR:`ghcr.io//` +- 镜像 tag 同时产出语义化版本(`1.2.3`)与 `latest` +- 部署端可 `docker compose pull && docker compose up -d` 升级 + +## 6. 故障排查 + +| 问题 | 解决方案 | +|------|---------| +| 端口被占用 | 修改 `.env` 中 `*_EXTERNAL_PORT` | +| 页面 404 | 确认构建产物已 COPY 到 `STATIC_FILES_DIR`,且 `SERVE_STATIC_FILES=true` | +| 服务启动失败 | 查看日志 `docker compose logs -f` | +| 配置未生效 | `docker compose config` 确认变量替换结果 | diff --git a/docs/rules/docs.md b/docs/rules/docs.md new file mode 100644 index 0000000..e7102a3 --- /dev/null +++ b/docs/rules/docs.md @@ -0,0 +1,56 @@ +--- +title: 文档规范 +description: 文档结构与格式规范 +keywords: [docs, index.md, 文档规范] +version: "2.0" +--- + +# 文档规范 + +本规范适用于任何软件项目的文档编写。 + +## 目录结构 + +- 深度≤3级 +- 每个目录必须有 `index.md` +- 文件名:`核心关键短语.md`,文件名必须为英语,文件内容必须是中文的 + +## 单文件要求 + +- 纯 Markdown 格式,单文件<500行 +- 头部固定6行: + ```yaml + --- + title: 标题 + version: 1.0 + keywords: [词1, 词2] + description: 20字内摘要 + --- + ``` + +## 文件索引 + +`index.md` 格式: +```md +# 目录名 +## 文件列表 +- [文件名1](文件名1.md):摘要 +- [文件名2](文件名2.md):摘要 + +## 子目录 +- [子目录名1](子目录名1/index.md) +- [子目录名2](子目录名2/index.md) +``` + +## 示例 + +``` +知识库/ +├── index.md +├── A/ +│ ├── index.md +│ └── A.md +└── B/ + ├── index.md + └── B.md +``` diff --git a/docs/rules/index.md b/docs/rules/index.md new file mode 100644 index 0000000..2819d5f --- /dev/null +++ b/docs/rules/index.md @@ -0,0 +1,17 @@ +--- +title: 通用规范 +description: 适用于任何软件项目的通用规范 +keywords: [规范, 通用, 指南] +version: "2.0" +--- + +# 通用规范 + +本目录包含适用于任何软件项目的通用规范和最佳实践。 + +## 文件列表 + +- [docs.md](docs.md): 文档规范 +- [code.md](code.md): 代码规范 +- [api-spec.md](api-spec.md): API 规范 +- [docker.md](docker.md): Docker 部署规范 diff --git a/scripts/check.sh b/scripts/check.sh new file mode 100755 index 0000000..1b4d47d --- /dev/null +++ b/scripts/check.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" + +cd "$PROJECT_ROOT" +echo "==> [MeetFlow] Backend pytest..." +.venv/bin/python -m pytest -q +echo "==> [MeetFlow] Frontend test & build..." +npm --prefix frontend test +npm --prefix frontend run build +echo "✓ 全部检查通过 (MeetFlow)"