# 360 看房软件技术架构说明

## 1. 技术栈推荐

### 前端

```text
Next.js
React
TypeScript
Tailwind CSS
Zustand
Three.js（全景渲染）
```

### 后端

```text
FastAPI
SQLAlchemy
MySQL 8.0
Alembic
Redis
Celery
```

### 存储

```text
Cloudflare R2 / AWS S3
```

### AI / 图像分析

```text
OpenCV
PyTorch
CLIP
视觉大模型 API
```

---

# 2. 整体架构

```text
                ┌─────────────────┐
                │     Frontend     │
                │ Next.js + React  │
                └────────┬────────┘
                         │
                         │ REST API + WebSocket（AI进度推送）
                         │
                ┌────────▼────────┐
                │     FastAPI      │
                │   Business API   │
                └────────┬────────┘
                         │
        ┌────────────────┼────────────────┐
        │                │                │
        │                │                │
 ┌──────▼──────┐  ┌──────▼──────┐  ┌──────▼──────┐
 │   MySQL 8.0  │  │   Redis      │  │ Object Store │
 │ Business DB  │  │ Task Queue   │  │ S3 / R2      │
 └─────────────┘  └─────────────┘  └─────────────┘
                         │
                         │ Celery 任务队列
                         │
                ┌────────▼────────┐
                │   AI Worker      │
                │ Image Analysis   │
                └─────────────────┘
```

---

# 3. 前端结构

```text
frontend/
├── app/
│   ├── dashboard/
│   ├── houses/
│   │   ├── [id]/
│   │   │   ├── edit/
│   │   │   └── preview/
│   ├── tour/
│   │   └── [slug]/
│   └── login/
│
├── components/
│   ├── panorama/
│   ├── hotspot/
│   ├── editor/
│   ├── room/
│   └── ui/
│
├── store/
│   ├── editorStore.ts
│   ├── hotspotStore.ts
│   ├── roomStore.ts
│   ├── tourStore.ts
│   └── aiSuggestionStore.ts
│
├── lib/
│   ├── api.ts
│   ├── auth.ts
│   └── types.ts
│
└── styles/
```

---

# 4. 后端结构

```text
backend/
├── app/
│   ├── main.py
│   ├── config.py
│   ├── database.py
│   │
│   ├── models/
│   │   ├── user.py
│   │   ├── house.py
│   │   ├── room.py
│   │   ├── panorama.py
│   │   ├── hotspot.py
│   │   ├── ai_job.py
│   │   ├── publish_version.py
│   │   └── permission.py
│   │
│   ├── routers/
│   │   ├── auth.py
│   │   ├── upload.py
│   │   ├── houses.py
│   │   ├── panoramas.py
│   │   ├── hotspots.py
│   │   ├── ai.py
│   │   └── publish.py
│   │
│   ├── schemas/
│   ├── services/
│   ├── tasks/
│   └── utils/
│
└── requirements.txt
```

---

# 5. AI Worker 结构

```text
ai-worker/
├── tasks/
│   ├── group_rooms.py
│   ├── detect_connections.py
│   ├── hotspot_prediction.py
│   └── validation.py
│
├── models/
│   ├── clip_model.py
│   ├── vision_model.py
│   └── matcher.py
│
└── utils/
```

---

# 6. 核心数据库表

## users

```text
用户账户信息
```

## houses

```text
房源信息
```

## floors

```text
楼层信息
```

## rooms

```text
房间分组
```

## panoramas

```text
360 图片节点
```

## hotspots

```text
图片之间的连接关系
```

## publish_versions

```text
发布版本管理（草稿/审核/发布/历史/回滚）
```

## ai_jobs

```text
AI 分析任务
```

## ai_suggestions

```text
AI 推荐热点/分组结果
```

## roles

```text
角色定义
```

## permissions

```text
权限定义
```

## role_permissions

```text
角色-权限映射
```

## user_house_roles

```text
用户在特定房源下的角色
```

---

# 7. Panorama 数据结构

```json
{
  "id": "pano_001",
  "roomId": "room_001",
  "imageUrl": "https://cdn.xxx/pano.jpg",
  "thumbnailUrl": "https://cdn.xxx/thumb.jpg",
  "sequence": 1,
  "defaultYaw": 90,
  "defaultPitch": 0,
  "captureOrder": 1,
  "position": {
    "x": 0,
    "y": 0,
    "z": 0
  },
  "metadata": {}
}
```

---

# 8. Hotspot 数据结构

```json
{
  "id": "hotspot_001",
  "fromPanoId": "pano_001",
  "toPanoId": "pano_002",
  "yaw": 85,
  "pitch": -25,
  "type": "forward",
  "label": "进入厨房",
  "confidence": 0.91,
  "status": "approved",
  "metadata": {}
}
```

---

# 9. 发布版本系统

## 9.1 版本生命周期

```text
                    ┌─────────┐
                    │  draft  │  编辑中的草稿
                    └────┬────┘
                         │ 提交审核
                         ▼
                 ┌──────────────┐
                 │ pending_review│  等待人工审核
                 └──────┬───────┘
                         │
              ┌──────────┼──────────┐
              │ 驳回      │ 通过      │ 撤回
              ▼          ▼          ▼
        ┌─────────┐ ┌──────────┐ ┌─────────┐
        │  draft  │ │ approved │ │  draft  │
        └─────────┘ └────┬─────┘ └─────────┘
                         │ 发布
                         ▼
                  ┌───────────┐
                  │ published │  线上生效版本
                  └─────┬─────┘
                        │
               ┌────────┼────────┐
               │ 修改    │ 回滚   │
               ▼        ▼        │
         ┌─────────┐ ┌──────────┐│
         │  draft  │ │archived  ││  回滚时当前版本
         │ (新版本) │ │(历史版本)││  标记为 rolled_back
         └─────────┘ └──────────┘│
                                 │
                        ┌────────┴──────┐
                        ▼               ▼
                  ┌──────────┐   ┌──────────┐
                  │archived  │   │  draft   │
                  │(被回滚版本)│   │(从旧版本 │
                  │           │   │ 复制恢复) │
                  └──────────┘   └──────────┘
```

## 9.2 publish_versions 表结构

```sql
CREATE TABLE publish_versions (
    id              VARCHAR(36) PRIMARY KEY,          -- UUID
    house_id        VARCHAR(36) NOT NULL,             -- 房源ID
    version_number  INT NOT NULL,                     -- 版本号，同一房源自增

    -- 版本状态
    status          ENUM(
                        'draft',            -- 草稿
                        'pending_review',   -- 等待审核
                        'approved',         -- 审核通过
                        'published',        -- 已发布
                        'archived',         -- 历史版本
                        'rolled_back'       -- 已被回滚
                    ) NOT NULL DEFAULT 'draft',

    -- 版本内容快照（完整保存发布时的房屋结构）
    snapshot_data   JSON NOT NULL,                    -- 快照数据

    -- 版本关系
    parent_version_id VARCHAR(36) DEFAULT NULL,       -- 基于哪个版本创建
    rolled_back_from_id VARCHAR(36) DEFAULT NULL,     -- 回滚时：从哪个版本回滚来的

    -- 时间
    created_at      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    submitted_at    DATETIME DEFAULT NULL,            -- 提交审核时间
    reviewed_at     DATETIME DEFAULT NULL,            -- 审核完成时间
    published_at    DATETIME DEFAULT NULL,            -- 发布时间

    -- 人员
    created_by      VARCHAR(36) NOT NULL,             -- 创建人 user_id
    reviewed_by     VARCHAR(36) DEFAULT NULL,         -- 审核人 user_id
    published_by    VARCHAR(36) DEFAULT NULL,         -- 发布人 user_id

    -- 备注
    changelog       TEXT DEFAULT NULL,                -- 版本变更说明
    review_notes    TEXT DEFAULT NULL,                -- 审核意见

    INDEX idx_house_id (house_id),
    INDEX idx_status (status),
    INDEX idx_house_status (house_id, status),
    UNIQUE KEY uk_house_version (house_id, version_number)
);
```

## 9.3 snapshot_data 结构

```json
{
  "house": {
    "id": "house_001",
    "title": "12 Example Street",
    "address": "Auckland",
    "slug": "12-example-street"
  },
  "floors": [
    {
      "id": "floor_001",
      "name": "一楼",
      "level": 1
    }
  ],
  "rooms": [
    {
      "id": "room_001",
      "floorId": "floor_001",
      "name": "客厅",
      "type": "living_room",
      "sortOrder": 1
    }
  ],
  "panoramas": [
    {
      "id": "pano_001",
      "roomId": "room_001",
      "imageUrl": "https://cdn.xxx/pano.jpg",
      "thumbnailUrl": "https://cdn.xxx/thumb.jpg",
      "sequence": 1,
      "defaultYaw": 90,
      "defaultPitch": 0,
      "captureOrder": 1,
      "position": { "x": 0, "y": 0, "z": 0 }
    }
  ],
  "hotspots": [
    {
      "id": "hotspot_001",
      "fromPanoId": "pano_001",
      "toPanoId": "pano_002",
      "yaw": 85,
      "pitch": -25,
      "type": "forward",
      "label": "进入厨房"
    }
  ],
  "aiSuggestions": []
}
```

## 9.4 版本操作流程

```text
┌──────────────────────────────────────────────────────┐
│ 操作           │ 前置状态        │ 目标状态         │
├──────────────────────────────────────────────────────┤
│ 创建草稿       │ -              │ draft            │
│ 编辑草稿       │ draft          │ draft            │
│ 提交审核       │ draft          │ pending_review   │
│ 撤回审核       │ pending_review │ draft            │
│ 审核通过       │ pending_review │ approved         │
│ 审核驳回       │ pending_review │ draft            │
│ 发布           │ approved       │ published        │
│ 修改已发布     │ published      │ draft（新版本号）  │
│ 回滚到历史版本 │ published      │ rolled_back      │
│                │                │ → draft（复制旧版本快照）│
│ 查看历史版本   │ 任意           │ 只读             │
└──────────────────────────────────────────────────────┘
```

## 9.5 前端版本管理入口

```text
编辑器顶部工具栏增加版本区域：

┌─────────────────────────────────────────────────────┐
│ [返回]  房源名称 ▼  版本 v3 (已发布) ▼  [提交审核]  │
├─────────────────────────────────────────────────────┤
│                                                     │
│  版本下拉菜单：                                      │
│  ├── v4 (草稿) ← 当前编辑                            │
│  ├── v3 (已发布) ← 线上版本                          │
│  ├── v2 (历史)                                       │
│  └── v1 (已回滚)                                     │
│                                                     │
│  点击历史版本 → 只读预览 + [回滚到此版本] 按钮        │
│                                                     │
└─────────────────────────────────────────────────────┘
```

---

# 10. 权限模型

## 10.1 角色定义

```text
┌────────────┬──────────────────────────────────────────┐
│ 角色        │ 说明                                     │
├────────────┼──────────────────────────────────────────┤
│ admin      │ 系统管理员，管理用户和全局配置              │
│ owner      │ 房源所有者，拥有该房源全部权限              │
│ editor     │ 编辑者，编辑热点、房间分组、上传图片         │
│ reviewer   │ 审核员，审核AI推荐结果和发布版本            │
│ viewer     │ 只读查看，预览草稿和已发布版本              │
└────────────┴──────────────────────────────────────────┘
```

## 10.2 细粒度权限列表

```text
┌──────────────────────────┬────────────────────────────┐
│ 权限标识                  │ 说明                       │
├──────────────────────────┼────────────────────────────┤
│ house:read               │ 查看房源基本信息            │
│ house:update             │ 修改房源信息                │
│ house:delete             │ 删除房源                    │
│ house:manage_members     │ 管理房源成员和角色           │
│                          │                            │
│ panorama:upload          │ 上传360图片                 │
│ panorama:read            │ 查看图片                    │
│ panorama:delete          │ 删除图片                    │
│ panorama:reorder         │ 调整图片顺序                │
│                          │                            │
│ room:create              │ 创建房间                    │
│ room:update              │ 修改房间（合并/拆分/改名）   │
│ room:delete              │ 删除房间                    │
│ room:reorder             │ 调整房间排序                │
│                          │                            │
│ hotspot:create           │ 创建热点                    │
│ hotspot:update           │ 修改热点                    │
│ hotspot:delete           │ 删除热点                    │
│ hotspot:batch_approve    │ 批量通过AI推荐热点          │
│                          │                            │
│ ai:suggestion:read       │ 查看AI推荐结果              │
│ ai:suggestion:approve    │ 采纳AI推荐                  │
│ ai:suggestion:reject     │ 拒绝AI推荐                  │
│ ai:job:create            │ 触发AI分析任务              │
│                          │                            │
│ publish:submit_review    │ 提交审核                    │
│ publish:review           │ 审核（通过/驳回）           │
│ publish:publish          │ 发布上线                    │
│ publish:rollback         │ 回滚到历史版本              │
│ publish:read_history     │ 查看历史版本                │
│                          │                            │
│ tour:preview             │ 预览草稿版                  │
│ tour:view_published      │ 查看已发布看房链接           │
└──────────────────────────┴────────────────────────────┘
```

## 10.3 角色-权限映射

```text
┌────────────────┬───────┬───────┬────────┬──────────┬────────┐
│ 权限            │ admin │ owner │ editor │ reviewer │ viewer │
├────────────────┼───────┼───────┼────────┼──────────┼────────┤
│ house:read      │  ✓   │  ✓   │   ✓    │    ✓     │   ✓   │
│ house:update    │  ✓   │  ✓   │   ✓    │          │       │
│ house:delete    │  ✓   │  ✓   │        │          │       │
│ house:manage_   │  ✓   │  ✓   │        │          │       │
│   members       │      │      │        │          │       │
│                │      │      │        │          │       │
│ panorama:upload │  ✓   │  ✓   │   ✓    │          │       │
│ panorama:read   │  ✓   │  ✓   │   ✓    │    ✓     │   ✓   │
│ panorama:delete │  ✓   │  ✓   │   ✓    │          │       │
│ panorama:reorder│  ✓   │  ✓   │   ✓    │          │       │
│                │      │      │        │          │       │
│ room:create     │  ✓   │  ✓   │   ✓    │          │       │
│ room:update     │  ✓   │  ✓   │   ✓    │          │       │
│ room:delete     │  ✓   │  ✓   │   ✓    │          │       │
│ room:reorder    │  ✓   │  ✓   │   ✓    │          │       │
│                │      │      │        │          │       │
│ hotspot:create  │  ✓   │  ✓   │   ✓    │          │       │
│ hotspot:update  │  ✓   │  ✓   │   ✓    │          │       │
│ hotspot:delete  │  ✓   │  ✓   │   ✓    │          │       │
│ hotspot:batch_  │  ✓   │  ✓   │   ✓    │    ✓     │       │
│   approve       │      │      │        │          │       │
│                │      │      │        │          │       │
│ ai:*:read       │  ✓   │  ✓   │   ✓    │    ✓     │       │
│ ai:*:approve    │  ✓   │  ✓   │   ✓    │    ✓     │       │
│ ai:*:reject     │  ✓   │  ✓   │   ✓    │    ✓     │       │
│ ai:job:create   │  ✓   │  ✓   │   ✓    │          │       │
│                │      │      │        │          │       │
│ publish:submit  │  ✓   │  ✓   │   ✓    │          │       │
│ publish:review  │  ✓   │  ✓   │        │    ✓     │       │
│ publish:publish │  ✓   │  ✓   │        │          │       │
│ publish:rollback│  ✓   │  ✓   │        │          │       │
│ publish:read_   │  ✓   │  ✓   │   ✓    │    ✓     │   ✓   │
│   history       │      │      │        │          │       │
│                │      │      │        │          │       │
│ tour:preview    │  ✓   │  ✓   │   ✓    │    ✓     │   ✓   │
│ tour:view_      │  ✓   │  ✓   │   ✓    │    ✓     │   ✓   │
│   published     │      │      │        │          │       │
└────────────────┴───────┴───────┴────────┴──────────┴────────┘
```

## 10.4 权限相关表结构

```sql
-- 角色表
CREATE TABLE roles (
    id          VARCHAR(36) PRIMARY KEY,
    name        VARCHAR(50) NOT NULL UNIQUE,     -- admin / owner / editor / reviewer / viewer
    description VARCHAR(255) DEFAULT NULL,
    is_system   TINYINT(1) NOT NULL DEFAULT 0,  -- 系统内置角色不可删除
    created_at  DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- 权限表
CREATE TABLE permissions (
    id          VARCHAR(36) PRIMARY KEY,
    code        VARCHAR(100) NOT NULL UNIQUE,    -- house:read / hotspot:create 等
    description VARCHAR(255) DEFAULT NULL,
    resource    VARCHAR(50) NOT NULL,            -- house / panorama / room / hotspot / ai / publish / tour
    action      VARCHAR(50) NOT NULL             -- read / create / update / delete / upload 等
);

-- 角色-权限映射
CREATE TABLE role_permissions (
    id            VARCHAR(36) PRIMARY KEY,
    role_id       VARCHAR(36) NOT NULL,
    permission_id VARCHAR(36) NOT NULL,
    UNIQUE KEY uk_role_permission (role_id, permission_id),
    FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
    FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
);

-- 用户在房源下的角色（核心关联表）
CREATE TABLE user_house_roles (
    id        VARCHAR(36) PRIMARY KEY,
    user_id   VARCHAR(36) NOT NULL,
    house_id  VARCHAR(36) NOT NULL,
    role_id   VARCHAR(36) NOT NULL,
    granted_by VARCHAR(36) DEFAULT NULL,         -- 授权人
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_user_house_role (user_id, house_id, role_id),
    FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);
```

## 10.5 权限判断逻辑

```text
用户请求操作某个房源资源时：

1. 检查 user_house_roles 中该用户在该房源下的所有角色
2. 汇总这些角色对应的所有权限
3. 判断是否包含请求操作所需的权限码
4. admin 角色拥有全局所有权限，不受房源限制

判断伪代码：
┌─────────────────────────────────────────────┐
│ def has_permission(user_id, house_id, perm):│
│     roles = get_user_roles(user_id, house_id)│
│     perms = get_role_permissions(roles)      │
│     return perm in perms                     │
└─────────────────────────────────────────────┘
```

---

# 11. AI 工作流程

```text
上传图片
    ↓
图片预处理（格式校验、生成缩略图、多分辨率切片）
    ↓
创建 AI Job
    ↓
AI 房间分组
    ↓
AI 判断相邻图片
    ↓
AI 生成热点推荐
    ↓
人工审核
    ↓
AI 二次验证
    ↓
提交发布审核
    ↓
审核通过 → 发布
```

---

# 12. 编辑器布局

```text
┌─────────────────────────────────────────────────────┐
│ 顶部工具栏                   版本 v4 (草稿) [操作]  │
├──────────┬──────────────────────────┬───────────────┤
│ 房间列表  │      360 预览区          │   属性栏       │
│          │                          │               │
│ [客厅]   │     热点编辑模式          │  热点类型      │
│ [厨房]   │     拖拽调整位置          │  目标房间      │
│ [主卧]   │                          │  置信度        │
│ [次卧]   │                          │  AI说明        │
│ [+房间]  │                          │               │
│          │                          │               │
├──────────┴──────────────────────────┴───────────────┤
│ AI 推荐面板（可折叠侧栏）                            │
│ ├── 建议热点: 客厅→厨房 (置信度 92%) [采纳] [忽略]   │
│ ├── 建议热点: 客厅→走廊 (置信度 78%) [采纳] [忽略]   │
│ └── 房间分组建议: 合并图3到客厅 (置信度 95%) [采纳]  │
└─────────────────────────────────────────────────────┘
```

---

# 13. 热点系统

## 热点类型

```text
forward       前进
back          返回
door          进门
stairs_up     上楼
stairs_down   下楼
room_enter    进入房间
quick_jump    快速跳转
info          信息点（展示文字/图片/链接）
```

## 精度策略

```text
热点不需要厘米级精确
连接关系必须准确
```

推荐误差：

```text
普通房间：
±15°

门口/楼梯：
±5° ~ ±10°
```

---

# 14. AI 推荐逻辑

## AI 负责

```text
房间分组
图片相邻关系
热点方向预测
门洞识别
走廊识别
地面识别
```

## AI 不直接负责

```text
最终发布
```

必须经过：

```text
规则过滤
+
人工审核
```

---

# 15. 发布前校验

系统自动检查：

```text
孤立节点
单向连接
低置信度热点
热点重叠
缺失房间名
错误反向连接（A→B yaw=90°, B→A 应≈270°）
缺失必要热点类型（房间入口/出口）
```

---

# 16. MVP 开发顺序

## 第一阶段（基础可用）

```text
用户注册/登录
图片上传 + 预处理（缩略图、多分辨率切片）
360 浏览器
手动热点增删改
房间分组（纯手动）
发布预览链接
移动端浏览
```

## 第二阶段（AI 辅助）

```text
AI 房间分组推荐
AI 推荐热点
人工审核后台
版本管理（草稿→审核→发布）
权限管理
```

## 第三阶段（空间导航）

```text
空间关系图
小地图基础版
自动路径规划
```

---

# 17. 核心设计原则

## 原则 1

```text
连接关系优先于热点精度
```

## 原则 2

```text
AI 只做推荐，不做最终决策
```

## 原则 3

```text
Graph 数据结构优先，拒绝线性图片列表
```

## 原则 4

```text
后台审核体验 == 用户浏览体验，同等重要
```

## 原则 5

```text
每次发布都是快照，历史版本可追溯可回滚
```

## 原则 6

```text
权限按房源隔离，角色决定操作范围
```

---

# 18. 最终产品定位

```text
AI 辅助的 360 室内空间导航编辑器
```

不是：

```text
普通 360 图片播放器
```
