237 lines
4.6 KiB
Markdown
237 lines
4.6 KiB
Markdown
# Moving Helper
|
|
|
|
这是一个面向可信家庭内网环境的小型搬家记录工具,当前采用轻量技术栈:
|
|
|
|
- FastAPI
|
|
- Jinja2 服务端渲染
|
|
- SQLAlchemy
|
|
- SQLite
|
|
- Pillow
|
|
- pytest / FastAPI TestClient
|
|
- Docker / Docker Compose
|
|
|
|
项目目标是小而稳、容易继续扩展。目前已经支持固定三层的数据结构、基础 CRUD,以及单图上传能力,但仍然没有加入搜索、OCR、AI 识别或其他扩展功能。
|
|
|
|
## 当前数据模型
|
|
|
|
这个项目不是无限树结构,而是固定最多 3 级:
|
|
|
|
- `Box`
|
|
- `Item`
|
|
- `SubItem`
|
|
|
|
关系如下:
|
|
|
|
- 一个 `Box` 包含多个 `Item`
|
|
- 一个 `Item` 属于一个 `Box`
|
|
- `Item` 通过 `is_container` 区分是否为“小容器”
|
|
- 只有 `is_container = true` 的 `Item` 才允许拥有 `SubItem`
|
|
- `SubItem` 是最后一级,不允许继续向下嵌套
|
|
|
|
结构固定为:
|
|
|
|
```text
|
|
Box
|
|
└── Item
|
|
└── SubItem
|
|
```
|
|
|
|
## 当前已支持
|
|
|
|
目前已支持的基础能力:
|
|
|
|
- Box 列表、详情、新建、编辑、删除
|
|
- Item 新建、详情、编辑、删除
|
|
- SubItem 新建、编辑、删除
|
|
- Box / Item / SubItem 单张图片上传、替换、删除、展示
|
|
- `/` 重定向到 `/boxes`
|
|
- Jinja2 模板渲染
|
|
- 静态文件挂载
|
|
- SQLite 持久化
|
|
- Docker 长期运行
|
|
- 基础自动化测试
|
|
|
|
删除规则:
|
|
|
|
- 删除 `Box` 时,会级联删除其下全部 `Item` 和对应 `SubItem`
|
|
- 删除容器型 `Item` 时,会级联删除其下 `SubItem`
|
|
|
|
## 图片能力说明
|
|
|
|
这一阶段的图片系统保持简单直接:
|
|
|
|
- `Box` 最多支持 1 张图片
|
|
- `Item` 最多支持 1 张图片
|
|
- `SubItem` 最多支持 1 张图片
|
|
- 支持上传、替换、删除
|
|
- 不支持多图
|
|
|
|
图片的主要用途是帮助识别物品、提高浏览效率、方便手机拍照后直接附加到记录中。
|
|
它不是一个原图归档系统。
|
|
|
|
### 图片处理方式
|
|
|
|
上传图片后,系统会使用 Pillow 做统一处理:
|
|
|
|
- 读取上传图片
|
|
- 去除 EXIF 元数据
|
|
- 转换为 JPEG
|
|
- 按最长边缩放到不超过 `1600px`
|
|
- 使用约 `80` 质量保存
|
|
- 将处理后的 JPEG 二进制直接写入 SQLite `BLOB`
|
|
|
|
同时还会记录:
|
|
|
|
- `image_mime_type`
|
|
- `image_width`
|
|
- `image_height`
|
|
|
|
图片访问通过普通 HTTP 路由返回 JPEG 数据,例如:
|
|
|
|
- `/boxes/{id}/image`
|
|
- `/items/{id}/image`
|
|
- `/subitems/{id}/image`
|
|
|
|
## 当前未实现
|
|
|
|
这一阶段仍然没有实现以下内容:
|
|
|
|
- 搜索
|
|
- 多图上传
|
|
- OCR
|
|
- AI 识别物品
|
|
- 图片标签
|
|
- 图片分类
|
|
- 登录 / 鉴权
|
|
- 标签系统
|
|
- 前后端分离
|
|
- 复杂 UI
|
|
|
|
## 项目结构
|
|
|
|
```text
|
|
.
|
|
├── app
|
|
│ ├── __init__.py
|
|
│ ├── config.py
|
|
│ ├── db.py
|
|
│ ├── images.py
|
|
│ ├── main.py
|
|
│ ├── models.py
|
|
│ ├── static
|
|
│ │ └── style.css
|
|
│ └── templates
|
|
│ ├── base.html
|
|
│ ├── boxes
|
|
│ ├── items
|
|
│ └── subitems
|
|
├── data
|
|
├── tests
|
|
│ ├── conftest.py
|
|
│ └── test_app.py
|
|
├── docker-compose.yml
|
|
├── Dockerfile
|
|
├── pytest.ini
|
|
├── README.md
|
|
└── requirements.txt
|
|
```
|
|
|
|
## 轻量配置
|
|
|
|
项目通过环境变量支持以下配置项:
|
|
|
|
- `DATABASE_URL`
|
|
- `HOST`
|
|
- `PORT`
|
|
|
|
默认值:
|
|
|
|
- `DATABASE_URL=sqlite:///./data/app.db`
|
|
- `HOST=0.0.0.0`
|
|
- `PORT=10000`
|
|
|
|
## 本地开发模式
|
|
|
|
推荐使用本地 Python `venv` 开发和调试。
|
|
|
|
### 1. 创建虚拟环境
|
|
|
|
```bash
|
|
python3 -m venv .venv
|
|
source .venv/bin/activate
|
|
```
|
|
|
|
### 2. 安装依赖
|
|
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
### 3. 启动开发服务器
|
|
|
|
```bash
|
|
uvicorn app.main:app --reload --host 0.0.0.0 --port 10000
|
|
```
|
|
|
|
访问:
|
|
|
|
```text
|
|
http://localhost:10000
|
|
```
|
|
|
|
本地默认数据库位置:
|
|
|
|
```text
|
|
./data/app.db
|
|
```
|
|
|
|
## Docker 部署模式
|
|
|
|
Docker / Compose 是这个项目面向长期运行环境的方式。
|
|
|
|
启动:
|
|
|
|
```bash
|
|
docker compose up --build
|
|
```
|
|
|
|
访问:
|
|
|
|
```text
|
|
http://localhost:10000
|
|
```
|
|
|
|
说明:
|
|
|
|
- 默认暴露 `10000` 端口
|
|
- `restart: unless-stopped`
|
|
- 容器使用 `1000:1000` 运行
|
|
- SQLite 文件持久化到宿主机 `./data/app.db`
|
|
- 容器重建不会丢失数据
|
|
|
|
备份时直接复制 SQLite 文件即可:
|
|
|
|
```text
|
|
./data/app.db
|
|
```
|
|
|
|
## 测试
|
|
|
|
运行测试:
|
|
|
|
```bash
|
|
python -m pytest
|
|
```
|
|
|
|
测试使用独立测试数据库,不会污染真实开发数据。
|
|
|
|
当前测试覆盖包括:
|
|
|
|
- Box / Item / SubItem 基础 CRUD
|
|
- 404 返回
|
|
- 非容器 Item 不能创建 SubItem
|
|
- Box / Item 删除后的级联删除
|
|
- 图片上传、转换为 JPEG、缩放、读取、替换、删除
|
|
- 无图片访问和非法图片上传等错误路径
|
|
- 关键 POST 请求后的重定向行为
|