2025-07-25 14:18:07 +08:00

14 KiB
Raw Permalink Blame History

“食话食说”项目设计文档

文档摘要

本文档是“食话食说”项目的综合技术设计与分析报告。通过对项目前后端代码库的系统性梳理本文档详细记录了项目的整体架构、前后端技术栈、数据库模型、API接口规范、前端路由与状态管理模式以及核心的用户交互流程。旨在为项目的后续开发、维护和团队协作提供一份清晰、准确、全面的技术参考。

目录

  1. 项目总体分析
    1. 项目简介
    2. 技术栈
  2. 后端 (API) 设计
    1. 数据库模型 (SQLAlchemy)
    2. API 数据结构 (Pydantic Schemas)
    3. API 端点 (Endpoints)
    4. 业务逻辑层 (CRUD)
    5. 安全与认证机制
  3. 前端 (UI) 设计
    1. 路由管理 (Vue Router)
    2. 状态管理 (Pinia)
    3. 组件结构与 API 交互
  4. 核心功能与交互流程
    1. 流程一:手机验证码登录 / 注册

1. 项目总体分析

1.1. 项目简介

本文档旨在对“食话食说”项目进行全面的技术分析和设计记录。项目采用前后端分离架构,前端基于 Vue.js 3 构建用户界面,后端使用 FastAPI 提供 API 服务,实现了包括用户认证、食品信息查询、扫码识别等核心功能。

1.2. 技术栈

1.2.1. 前端 (shihuashishuo-ui)

  • 核心框架: Vue.js 3 (vue: ^3.5.17)
  • 路由管理: Vue Router (vue-router: ^4.5.1)
  • 状态管理: Pinia (pinia: ^3.0.3)
  • 开发与构建工具: Vite (vite: npm:rolldown-vite@^7.0.9)
  • 编程语言: TypeScript (typescript: ~5.8.0)
  • 单元测试: Vitest (vitest: ^3.2.4)
  • 端到端测试: Playwright (@playwright/test: ^1.53.1)
  • 代码规范与格式化: ESLint, Prettier, Oxlint

1.2.2. 后端 (shihuashishuo-api)

  • 核心框架: FastAPI
  • Web 服务器: Uvicorn
  • ORM (对象关系映射): SQLAlchemy
  • 数据校验: Pydantic
  • 安全与认证: python-jose[cryptography], passlib, bcrypt
  • 文件上传支持: python-multipart
  • 数据库: SQLite (根据 shihuashishuo.db 文件推断)

2. 后端 (API) 设计

2.1. 数据库模型 (SQLAlchemy)

数据库模型定义在 shihuashishuo-api/models.py 中,使用 SQLAlchemy ORM。

表名 (__tablename__) 模型类 (class) 描述 关键字段
users User 存储用户信息 id, phone_number, hashed_password, avatar_url
user_preferences UserPreference 存储用户的个人偏好,如过敏原、健康状况等 id, category, value, user_id
foods Food 存储食品的基本信息 id, barcode, name, brand, ingredients
search_history SearchHistory 记录用户的搜索历史 id, query, user_id

2.2. API 数据结构 (Pydantic Schemas)

API的数据输入输出规范定义在 shihuashishuo-api/schemas.py 中,使用 Pydantic 模型进行数据校验和序列化。

  • 用户相关 (User*):
    • UserBase: 用户基础信息(手机号、头像)。
    • UserCreate: 用于创建用户,包含密码。
    • UserCodeLogin: 用于验证码登录。
    • UserPasswordLogin: 用于密码登录。
    • User: API返回的用户信息包含id和创建时间。
    • PasswordSet: 用于设置或修改密码。
  • 认证相关 (Token):
    • Token: 登录成功后返回的 access_token
  • 食品相关 (Food*):
    • FoodBase: 食品基础信息。
    • FoodCreate: 用于创建食品条目。
    • Food: API返回的食品信息。
  • 用户偏好相关 (UserPreference*, OnboardingPreferences):
    • UserPreferenceBase: 用户偏好基础信息。
    • UserPreferenceCreate: 用于创建用户偏好。
    • UserPreference: API返回的用户偏好信息。
    • OnboardingPreferences: 用于处理引导流程中用户提交的批量偏好。
  • 搜索历史相关 (SearchHistory*):
    • SearchHistoryBase: 搜索历史基础信息。
    • SearchHistoryCreate: 用于创建搜索历史。
    • SearchHistory: API返回的搜索历史信息。

2.3. API 端点 (Endpoints)

API 的主要逻辑和路由定义在 shihuashishuo-api/main.py 中。

2.3.1. 认证路由 (/api/v1/auth)

方法 路径 函数名 描述 是否需要认证
POST /send-verification-code send_verification_code 发送手机验证码(当前为模拟)
POST /login login 使用手机和验证码登录或注册
POST /login/password login_with_password 使用手机和密码登录
PUT /users/me/password set_password_for_current_user 为当前登录用户设置密码

2.3.2. 其他核心路由

方法 路径 函数名 描述 是否需要认证
GET / read_root API 根路径,返回欢迎信息
GET /api/v1/users/check-phone-existence/ check_phone_existence 检查手机号是否已注册
POST /api/v1/food/ create_food_entry 创建新的食品条目
GET /api/v1/food/{barcode} read_food_by_barcode 根据条形码查询食品信息
POST /api/v1/users/me/preferences update_user_preferences 为当前用户批量更新偏好设置
POST /api/v1/search/history create_search_history_entry 创建一条搜索历史记录 可选

2.4. 业务逻辑层 (CRUD)

数据库的增、删、改、查CRUD操作被封装在 shihuashishuo-api/crud.py 文件中,供 API 路由调用。

  • get_user_by_phone_number: 根据手机号查询用户。
  • create_user: 创建新用户,如果提供了密码,则进行哈希存储。
  • authenticate_user: 验证用户密码是否正确。
  • set_user_password: 为指定用户设置或更新密码。
  • get_food_by_barcode: 根据条形码查询食品。
  • create_food: 创建新的食品条目。
  • create_user_preferences: 批量创建用户偏好,会先删除旧记录。
  • create_search_history: 创建搜索历史记录。

2.5. 安全与认证机制

项目的认证与安全相关功能定义在 shihuashishuo-api/security.py 中。

  • 认证方式: 基于 JWT (JSON Web Tokens) 的 Bearer Token 认证。
  • Token 生成:
    • 使用 python-jose 库生成 HS256 签名的 JWT。
    • 访问令牌默认有效期为 30 分钟 (ACCESS_TOKEN_EXPIRE_MINUTES)。
  • 密码处理:
    • 使用 passlibbcrypt 算法对用户密码进行哈希处理和验证。
  • 依赖注入:
    • get_current_user: 一个 FastAPI 依赖项,用于从请求头中解析 Token验证并获取当前登录的用户信息。需要认证的路由都会依赖此函数。
    • get_current_user_optional: get_current_user 的可选版本,在没有提供 Token 时返回 None 而非抛出异常。
  • 安全风险提示:
    • SECRET_KEY 目前是硬编码在代码中的,在生产环境中应使用环境变量等更安全的方式进行管理。

3. 前端 (UI) 设计

3.1. 路由管理 (Vue Router)

前端路由配置在 shihuashishuo-ui/src/router/index.ts 中,负责管理页面导航。

  • 路由模式: HTML5 History 模式 (createWebHistory)。
  • 主要路由分组:
    • 通用基础页: 包含闪屏页 (/splash)、登录页 (/login)、引导页 (/onboarding) 等独立页面。
    • 主应用布局 (/app): 包含一个带有底部导航栏的 MainLayout,嵌套了首页 (/home)、发现 (/discover)、我的 (/me) 等核心功能页面。
    • 独立功能页: 包含扫码页 (/scan)、搜索页 (/search)、结果页 (/result/:id) 等无底部导航栏的页面。
  • 全局路由守卫 (router.beforeEach):
    • 认证检查: 保护需要登录才能访问的页面,未登录用户会被重定向到登录页。
    • 引导流程检查: 已登录但未完成引导流程的用户会被强制导向引导页。
    • 状态一致性: 防止已登录用户重复访问登录页或引导页。

3.2. 状态管理 (Pinia)

全局状态管理由 Pinia 实现,核心是 shihuashishuo-ui/src/stores/auth.ts

  • 持久化: 关键认证状态(如 token, isLoggedIn)通过 localStorage 进行持久化,防止刷新页面后状态丢失。
  • 核心状态 (state):
    • token: 存储用户的 JWT 访问令牌。
    • isLoggedIn: 布尔值,表示用户当前的登录状态。
    • hasCompletedOnboarding: 布尔值,表示用户是否已完成首次引导流程。
    • isNewUser: 布尔值,用于判断用户在登录后是否为新注册用户,以决定是否跳转到引导页。
  • 核心动作 (actions):
    • setToken: 登录成功后调用,保存 token 并更新状态。
    • logout: 清除所有认证状态和本地存储。
    • completeOnboarding: 标记引导流程完成。
    • setPassword, passwordLogin: 封装了调用后端认证相关 API 的 fetch 请求。

3.3. 组件结构与 API 交互

  • 组件化: 项目遵循 Vue 的组件化思想,将页面拆分为可复用的组件。页面级组件存放在 src/views,通用组件可以放在 src/components (当前项目暂未大量使用)。
  • 页面结构:
    • 通用基础页: 存放登录、注册、引导、闪屏等与核心业务逻辑解耦的页面。
    • 核心体验页: 存放与食品查询相关的核心功能页面。
    • 根目录 views: 存放构成主应用导航的五个一级页面。
  • API 交互模式 (以 PasswordLoginView.vue 为例):
    1. 视图层 (View): 负责渲染 UI 和接收用户输入(如手机号、密码)。
    2. 触发动作: 用户操作(如点击登录按钮)会调用一个在 <script setup> 中定义的方法。
    3. 调用状态管理 (Store): 该方法不直接发起 API 请求,而是调用 Pinia Store (authStore) 中对应的 action (如 authStore.passwordLogin()),并将用户输入作为参数传入。
    4. Store 执行 API 请求:authStoreaction 内部,使用 fetch 向后端发送请求,并处理响应。
    5. 更新状态: API 请求成功后,action 会更新 Store 中的状态(如 token, isLoggedIn)。
    6. 响应式更新: 由于组件依赖于 Store 中的状态,状态的改变会通过 Vue 的响应式系统自动反馈到 UI 上。
    7. 导航: action 执行完毕后,视图层根据返回结果或更新后的状态,使用 vue-router 进行页面跳转。

这种模式将视图渲染、状态管理和 API 通信清晰地分离开来,是 Vue 生态中的最佳实践之一。

4. 核心功能与交互流程

本章节将整合前后端的分析结果,对关键的用户功能流程进行详细描述。

4.1. 流程一:手机验证码登录 / 注册

这是应用最核心的用户入口流程,涵盖了新用户注册和老用户登录两种情况。

4.1.1. 流程描述

  1. 用户输入手机号: 用户在登录页 (LoginView) 输入手机号码,点击“发送验证码”。
  2. 前端请求验证码: 前端调用后端 POST /api/v1/auth/send-verification-code 接口。
  3. 后端发送验证码: 后端收到请求,(当前为模拟)生成一个验证码(如 "111111"并返回给前端。在生产环境中此处应调用短信服务商API。
  4. 用户输入验证码: 用户收到验证码后,在页面上输入,并点击“登录”。
  5. 前端执行登录:
    • 前端调用 Pinia Store 中的 authStore.setToken (或类似逻辑),该 action 会向后端 POST /api/v1/auth/login 发送请求,请求体包含手机号和验证码。
  6. 后端处理登录:
    • 后端验证验证码是否正确。
    • 验证通过后,调用 crud.get_user_by_phone_number 检查该手机号是否存在。
    • 如果用户不存在 (新用户): 调用 crud.create_user 创建一个新用户记录,并标记 is_new_user = True
    • 如果用户已存在 (老用户): 直接获取该用户信息,is_new_user = False
    • 使用 security.create_access_token 为该用户生成一个 JWT。
    • access_tokenis_new_user 标志返回给前端。
  7. 前端处理响应:
    • authStore 将收到的 tokenis_new_user 状态存入 localStorage
    • 如果是新用户: isNewUser 状态为 true,路由守卫将用户重定向到引导页 (/onboarding)。
    • 如果是老用户: isNewUser 状态为 false,路由守卫将用户重定向到主页 (/app/home)。

4.1.2. 序列图 (Mermaid.js)

sequenceDiagram
    participant User as 用户
    participant Frontend as 前端 (Vue)
    participant Backend as 后端 (FastAPI)
    participant DB as 数据库

    User->>Frontend: 1. 输入手机号,点击发送验证码
    Frontend->>Backend: 2. POST /api/v1/auth/send-verification-code
    Backend-->>Frontend: 3. 返回模拟验证码 "111111"
    User->>Frontend: 4. 输入验证码,点击登录
    Frontend->>Backend: 5. POST /api/v1/auth/login (含手机号和验证码)
    
    Backend->>Backend: 6.1. 校验验证码
    Backend->>DB: 6.2. get_user_by_phone_number()
    
    alt 新用户
        DB-->>Backend: 6.3. 用户不存在
        Backend->>DB: 6.4. create_user()
        DB-->>Backend: 6.5. 返回新用户信息
        Backend->>Backend: 6.6. 生成JWT, is_new_user = true
    else 老用户
        DB-->>Backend: 6.3. 返回用户信息
        Backend->>Backend: 6.6. 生成JWT, is_new_user = false
    end

    Backend-->>Frontend: 7. 返回 { access_token, is_new_user }
    Frontend->>Frontend: 8. 保存Token, 更新Store状态
    
    alt is_new_user is true
        Frontend->>User: 9. 重定向到引导页 (/onboarding)
    else is_new_user is false
        Frontend->>User: 9. 重定向到主页 (/app/home)
    end