# Strapi 个人账本系统设计

URL: https://caijiao.org/posts/36
Source: docs/posts/36.md
Description: 本文介绍如何使用 Strapi 设计一个简单的个人账本系统，包括用户注册、类别管理、入账记录以及收入/支出类型设计。

本文介绍如何使用 **Strapi** 设计一个简单的个人账本系统，满足以下需求：

## 需求分析

1. **用户（User）**
   - 用户可以注册、登录
   - 系统默认使用 Strapi 自带的用户管理

2. **类别（Category）**
   - 用户可以新建、编辑、删除自己的类别
   - 示例类别：吃饭、教育
   - 每个类别只能归属于创建者

3. **类型（Type）**
   - 系统固定：收入（Income）和支出（Expense）
   - 不允许用户修改或删除

4. **入账记录（Transaction）**
   - 记录金额、类别、类型和日期
   - 用户只能操作自己的记录

## 数据模型设计

### 用户（User）

Strapi 默认提供：

- `username`
- `email`
- `password`

无需额外建表。

### 类型（Type）

系统固定枚举：

- Collection Name: `Type`
- 字段：
  - `name`（枚举）：`income` / `expense`
- 系统初始化时创建两条数据
- 只读，不允许用户修改

### 类别（Category）

用户自定义：

- Collection Name: `Category`
- 字段：
  - `name`（string）：类别名称
  - `user`（relation）：`User` → `Category`（many-to-one）
- 权限：
  - 用户只能操作自己的类别
  - 查询只返回自己的类别

### 入账记录（Transaction）

记录每笔账目：

- Collection Name: `Transaction`
- 字段：
  - `amount`（number）：金额
  - `category`（relation）：`Category` → `Transaction`（many-to-one）
  - `type`（relation）：`Type` → `Transaction`（many-to-one）
  - `user`（relation）：`User` → `Transaction`（many-to-one）
  - `date`（date）：日期，默认当前时间
  - `note`（string，可选）：备注
- 权限：
  - 用户只能查看、编辑、删除自己的交易
  - `type` 只能选择系统已有的“收入/支出”

## 权限控制

1. **Category**
   - 创建、更新、删除：仅允许自己操作
   - 查询：仅返回自己的数据

2. **Transaction**
   - 创建、更新、删除：仅允许自己操作
   - 查询：仅返回自己的数据

3. **Type**
   - 只读，所有用户可查询

## Strapi 实现细节

### 枚举类型

在 Transaction 中可直接使用枚举：

```json
{
  "type": "enumeration",
  "enum": ["income", "expense"]
}
````

### Policy 示例（限制用户操作自己的类别）

```js
// ./src/policies/isOwner.js
module.exports = async (ctx, next) => {
  const { id } = ctx.params;
  const entity = await strapi.db.query('api::category.category').findOne({ where: { id } });
  if (!entity || entity.user.id !== ctx.state.user.id) {
    return ctx.unauthorized('You can only access your own data');
  }
  await next();
};
```

## 系统初始化

1. 创建 Type 数据：

   - `income`
   - `expense`
2. 用户注册后，可创建自己的 Category

## 数据访问示例

### 查询用户交易

```js
const transactions = await strapi.db.query('api::transaction.transaction').findMany({
  where: { user: { id: ctx.state.user.id } },
  populate: ['category', 'type']
});
```

### 创建交易

```js
await strapi.db.query('api::transaction.transaction').create({
  data: {
    amount: 100,
    category: 1,  // 自己的 category id
    type: 1,      // income 或 expense id
    user: ctx.state.user.id
  }
});
```

---

这样就完成了一个 **基于 Strapi 的个人账本系统设计**，实现了用户注册、类别管理、入账记录及收入/支出类型控制。
