From 23588b584fca752201e40631d983836f4227f2cf Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Thu, 21 May 2026 10:00:46 +0800 Subject: [PATCH] Add Phase 1 infrastructure setup and implementation plan - infrastructure-setup.md: MinIO bucket, access key, PostgreSQL database/user/table deployment guide - implementation-plan.md: backend (FastAPI) and Android (Flutter) implementation roadmap - .gitignore: exclude credential YAML files (connections-remote.yaml, connections-local.yaml) Co-Authored-By: Claude Opus 4.6 --- .gitignore | 4 + docs/implementation-plan.md | 131 ++++++++++++++++++++++ docs/infrastructure-setup.md | 206 +++++++++++++++++++++++++++++++++++ 3 files changed, 341 insertions(+) create mode 100644 docs/implementation-plan.md create mode 100644 docs/infrastructure-setup.md diff --git a/.gitignore b/.gitignore index ea8274b..ae6af1a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,9 @@ Thumbs.db .env .env.* +# Credentials +docs/connections-remote.yaml +docs/connections-local.yaml + # Claude .claude/ diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md new file mode 100644 index 0000000..2ab8477 --- /dev/null +++ b/docs/implementation-plan.md @@ -0,0 +1,131 @@ +# SnapLedger Phase 1 实施计划 + +> **日期:** 2026-05-21 +> **范围:** 后端 (FastAPI) + Android 端 (Flutter/Dart) +> **目标:** 跑通端到端数据流 — 截图 → 上传 → 存储 → 入库 + +## 技术决策 + +| 决策项 | 选择 | 理由 | +|---|---|---| +| Android 框架 | Flutter / Dart | 主仓库 README 已确定 | +| 后端框架 | Python FastAPI | 已确定 | +| 后端部署 | Docker 容器 | 服务器已有 Docker 环境 | +| API 鉴权 | 静态 Token (Header) | Phase 1 个人使用,简单直接 | +| 数据库 | PostgreSQL 18 (已部署) | — | +| 对象存储 | MinIO (已部署) | — | + +## 开发与部署环境 + +| 环境 | 位置 | 用途 | 配置文件 | +|---|---|---|---| +| 开发机 | 当前主机 (Windows) | 编码、调试、本地运行后端 | `docs/connections-remote.yaml` | +| 服务器 | `Remote_MisakaServer:/home/misakafiles/` | 生产部署 | `docs/connections-local.yaml` | + +**配置文件说明:** +- `connections-remote.yaml` — 当前主机开发时使用,通过公网域名/cpolar 隧道连接服务器上的 MinIO 和 PostgreSQL +- `connections-local.yaml` — 服务器部署时使用,MinIO 和 PostgreSQL 均为 localhost 连接 +- 两个文件均已在 `.gitignore` 中,不提交到仓库 + +--- + +## Part A: 后端 (backend/) + +### A1. 项目初始化 + +- 创建 `pyproject.toml` 管理依赖 +- 依赖清单:`fastapi`, `uvicorn[standard]`, `boto3` (S3), `psycopg[binary]` (PostgreSQL), `python-multipart`, `pydantic`, `pyyaml` +- 创建 `config.example.yaml` 声明配置模板 +- 创建 `.gitignore` + +### A2. 项目结构 + +``` +backend/ +├── app/ +│ ├── __init__.py +│ ├── main.py # FastAPI app 入口 +│ ├── config.py # Settings (Pydantic, 读 config.yaml) +│ ├── routers/ +│ │ │ └── upload.py # POST /api/upload 路由 +│ ├── services/ +│ │ ├── minio.py # MinIO 上传逻辑 +│ │ └── database.py # PostgreSQL 写入逻辑 +│ └── models/ +│ └── transaction.py # Pydantic / SQL 模型 +├── config.example.yaml # 配置模板 (无敏感信息) +├── pyproject.toml +├── Dockerfile +├── docker-compose.yml +└── .gitignore +``` + +### A3. 核心功能实现 + +| 功能 | 说明 | +|---|---| +| `config.py` | 使用 Pydantic 模型读取 `config.yaml`:MinIO 连接、PG 连接、API Token | +| `POST /api/upload` | 接收 multipart/form-data:图片文件 + original_filename + user_note,鉴权 Token 校验 | +| `services/minio.py` | 生成 Object Key (`YYYY/MM/DD/.`),调用 S3 PutObject 上传到 `snapledger` 桶 | +| `services/database.py` | 写入 `transactions` 表:image_object_key, original_filename, user_note, upload_time, process_status=PENDING | + +### A4. 本地开发验证 + +- 将 `docs/connections-remote.yaml` 复制为 `backend/config.yaml` +- 在当前主机上使用 `.venv` 运行 FastAPI +- `curl -X POST` 模拟上传,确认 MinIO 有文件、PG 有记录 + +### A5. 服务器部署 + +1. SSH 到 `Remote_MisakaServer` +2. `cd /home/misakafiles/ && git clone <主仓库地址> && cd SnapLedger && git submodule update --init` +3. 将 `docs/connections-local.yaml` 复制为 `backend/config.yaml` +4. `cd backend && docker compose up -d --build` +5. 验证容器运行正常,从 Android 端实际测试 + +--- + +## Part B: Android 端 (android/) + +### B1. 项目初始化 + +- `flutter create` 创建 Flutter 项目 +- 添加依赖:`http` (网络请求)、`path_provider` (文件路径)、`shared_preferences` (可选,缓存 Token) +- 配置 AndroidManifest.xml:注册 Share Intent receiver + +### B2. 核心功能实现 + +| 功能 | 说明 | +|---|---| +| **Share Intent 接收** | Android 原生层 (`MethodChannel`) 注册 `ACTION_SEND` intent,接收图片 URI 和原始文件名 | +| **记账弹窗 UI** | Flutter 半屏弹窗:图片缩略图预览 + 备注输入框 + 提交/取消按钮 | +| **网络上传模块** | 构造 multipart POST 请求,附带图片字节流 + original_filename + user_note + Token Header | +| **失败重试** | 上传失败时本地缓存请求,网络恢复后重试 | + +### B3. 验证 + +- 手机截图 → 分享到 SnapLedger → 弹窗 → 提交 → 确认 MinIO 和 PG 有数据 + +--- + +## 实施顺序 + +``` +A1 → A2 → A3 → A4(本地验证) → A5(服务器部署) → B1 → B2 → B3 + ↑ + 后端就绪后开始 +``` + +**先完成后端,再实现 Android 端。** 后端完成后可以用 curl 验证,不依赖客户端。 + +--- + +## 产出文件清单 + +| 文件 | 位置 | 说明 | +|---|---|---| +| 后端代码 | `backend/app/` | FastAPI 应用 | +| Dockerfile | `backend/Dockerfile` | 后端容器镜像 | +| docker-compose.yml | `backend/docker-compose.yml` | 后端容器编排 | +| Flutter 项目 | `android/lib/` | Flutter/Dart 源码 | +| AndroidManifest | `android/android/app/src/main/AndroidManifest.xml` | Share Intent 注册 | diff --git a/docs/infrastructure-setup.md b/docs/infrastructure-setup.md new file mode 100644 index 0000000..68efe9c --- /dev/null +++ b/docs/infrastructure-setup.md @@ -0,0 +1,206 @@ +# SnapLedger 基础设施实施文档 + +> **目标服务器:** `Remote_MisakaServer` +> **日期:** 2026-05-21 +> **对应 PRD:** Phase 1 - 数据通道基建 + +## 1. 服务器现有环境 + +### 1.1 MinIO (systemd 服务) + +| 项目 | 值 | +|---|---| +| 部署方式 | systemd 原生服务 | +| 二进制路径 | `/usr/local/bin/minio` | +| API 端口 | `9002` | +| Console 端口 | `9001` | +| 数据目录 | `/mnt/disk1` | +| 管理账号 | `myminioadmin` / `myminioadmin` | +| mc 客户端 | 已安装,本地 alias `mylocal` → `localhost:9002` | + +### 1.2 PostgreSQL (systemd 服务) + +| 项目 | 值 | +|---|---| +| 部署方式 | systemd 原生服务 | +| 版本 | PostgreSQL 18.3 (Ubuntu 18.3-1.pgdg22.04+1) | +| 二进制路径 | `/usr/lib/postgresql/18/bin/postgres` | +| 端口 | `5432` | +| 数据目录 | `/var/lib/postgresql/18/main` | +| 配置文件 | `/etc/postgresql/18/main/postgresql.conf` | +| 认证方式 | 本地 peer / 远程 scram-sha-256 | +| 管理账号 | `postgres` (系统用户,通过 `sudo -u postgres psql` 访问) | +| 现有数据库 | CompanyDB, ai_image_vault, postgres | +| 现有角色 | admin, companydb_user, img_vault, mcp_user, postgres | + +--- + +## 2. 实施计划 + +### Step 1: MinIO - 创建 Bucket + +- **操作:** 使用 `mc` 创建名为 `snapledger` 的存储桶 +- **用途:** 存储用户上传的支付截图 +- **策略:** 限制 Bucket 仅允许应用访问,不公开 + +### Step 2: MinIO - 创建 Access Key + +- **操作:** 使用 `mc admin user add` 创建专用访问密钥 +- **用途:** 后端 FastAPI 服务使用此密钥上传/读取图片 +- **权限:** 仅对 `snapledger` 桶有读写权限 + +### Step 3: PostgreSQL - 创建数据库与用户 + +- **操作:** 创建 `snapledger` 数据库和专用用户 `snapledger_user` +- **权限:** 该用户仅拥有 `snapledger` 数据库的完整权限 + +### Step 4: PostgreSQL - 创建基础表 + +- **操作:** 根据 PRD 数据模型创建 `transactions` 表 +- **内容:** 包含原始数据层、核心业务层、审计运维层全部字段 + +--- + +## 3. 详细操作命令 + +### 3.1 MinIO - 创建 Bucket + +```bash +# 在服务器上执行 +mc mb mylocal/snapledger +``` + +### 3.2 MinIO - 创建 Access Key 并授权 + +```bash +# 创建策略文件,限制仅访问 snapledger 桶 +cat > /tmp/snapledger-policy.json << 'EOF' +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "s3:PutObject", + "s3:GetObject", + "s3:DeleteObject", + "s3:ListBucket" + ], + "Resource": [ + "arn:aws:s3:::snapledger", + "arn:aws:s3:::snapledger/*" + ] + } + ] +} +EOF + +# 创建策略 +mc admin policy create mylocal snapledger-policy /tmp/snapledger-policy.json + +# 创建服务账号 (Access Key / Secret Key 由 mc 自动生成) +mc admin user svcacct add mylocal myminioadmin --description 'SnapLedger app service account' + +# 将策略绑定到新生成的服务账号 (使用上一步输出的 Access Key) +mc admin policy attach mylocal snapledger-policy --user <生成的AccessKey> +``` + +### 3.3 PostgreSQL - 创建数据库与用户 + +```bash +# 在服务器上通过 postgres 系统用户执行 +# 先生成随机密码 +PG_PASS=$(openssl rand -base64 24) +sudo -u postgres psql + +# SQL 语句 +CREATE USER snapledger_user WITH PASSWORD '${PG_PASS}'; +CREATE DATABASE snapledger OWNER snapledger_user; +GRANT ALL PRIVILEGES ON DATABASE snapledger TO snapledger_user; +``` + +### 3.4 PostgreSQL - 创建基础表 + +```bash +# 连接到 snapledger 数据库 +sudo -u postgres psql -d snapledger +``` + +```sql +-- 授予 schema 权限 +GRANT ALL ON SCHEMA public TO snapledger_user; + +-- 创建 transactions 表 +CREATE TABLE IF NOT EXISTS transactions ( + -- 原始数据层 + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + image_object_key VARCHAR NOT NULL, + original_filename VARCHAR, + user_note TEXT, + upload_time TIMESTAMPTZ NOT NULL DEFAULT NOW(), + process_status VARCHAR(20) NOT NULL DEFAULT 'PENDING' + CHECK (process_status IN ('PENDING','PROCESSING','COMPLETED','FAILED')), + + -- 核心业务层 (AI 填充) + transaction_type VARCHAR(20) CHECK (transaction_type IN ('EXPENSE','INCOME','TRANSFER')), + amount DECIMAL(10,2), + merchant_name VARCHAR, + source_app VARCHAR, + transaction_date TIMESTAMPTZ, + category VARCHAR, + order_number VARCHAR, + + -- 审计运维层 + llm_raw_response JSONB, + + -- 索引与约束 + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +-- 创建索引 +CREATE INDEX idx_transactions_process_status ON transactions (process_status); +CREATE INDEX idx_transactions_upload_time ON transactions (upload_time DESC); +CREATE INDEX idx_transactions_source_app ON transactions (source_app); +CREATE INDEX idx_transactions_order_number ON transactions (order_number) WHERE order_number IS NOT NULL; + +-- 授权 +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO snapledger_user; +GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO snapledger_user; +``` + +--- + +## 4. 预期产出 + +完成以上步骤后,将产出以下资源: + +### MinIO + +| 资源 | 名称 | 说明 | +|---|---|---| +| Bucket | `snapledger` | 存储支付截图 | +| Access Key | 服务账号,Access Key / Secret Key 自动生成 | 后端服务专用 | +| Policy | `snapledger-policy` | 仅限 `snapledger` 桶读写 | + +### PostgreSQL + +| 资源 | 名称 | 说明 | +|---|---|---| +| Database | `snapledger` | 应用主数据库 | +| User | `snapledger_user` | 应用专用账号 | +| Table | `transactions` | 交易记录核心表 | +| Indexes | 4 个 | 加速状态查询、时间排序、来源筛选、订单去重 | + +### 连接信息 + +详见 `docs/connections.yaml`(已加入 `.gitignore`,不会提交到仓库)。 + +--- + +## 5. 验证步骤 + +1. **MinIO Bucket:** `mc ls mylocal/snapledger` 确认桶存在 +2. **MinIO Access Key:** 使用新密钥配置 mc alias 并上传测试文件 +3. **PostgreSQL 连接:** `sudo -u postgres psql -d snapledger -c "\dt"` 确认表已创建 +4. **表结构验证:** `\d transactions` 确认字段与索引完整