docs: require real facility hierarchy
This commit is contained in:
@@ -110,3 +110,73 @@ await database.transaction(async (transaction) => {
|
||||
await transaction.update(elders).set({ status: "active" }).where(eq(elders.id, elderId));
|
||||
});
|
||||
```
|
||||
|
||||
## Scenario: Facility Room Creation Without Fabricated Hierarchy
|
||||
|
||||
### 1. Scope / Trigger
|
||||
|
||||
- Trigger: changing facility room creation APIs or any UI that creates rooms.
|
||||
- Applies because `rooms.floorId` is required by schema, but the system must not create
|
||||
fake campus/building/floor records to satisfy that foreign key.
|
||||
|
||||
### 2. Signatures
|
||||
|
||||
- `POST /api/facilities/rooms`
|
||||
- Request: `{ name: string; code: string; floorId: string; capacity?: number }`
|
||||
- Response: `ApiResult<{ room: typeof rooms.$inferSelect }>`
|
||||
|
||||
### 3. Contracts
|
||||
|
||||
- `floorId` must refer to an existing `floors.id` in the authenticated active organization.
|
||||
- `capacity` is optional; omitted means schema/product default `1`.
|
||||
- If `capacity` is supplied, it must be a positive integer.
|
||||
- The handler may insert only the `rooms` row. It must not insert `campuses`,
|
||||
`buildings`, or `floors` as placeholder hierarchy.
|
||||
|
||||
### 4. Validation & Error Matrix
|
||||
|
||||
- Missing active organization -> `400` / `请选择机构后维护房间`.
|
||||
- Missing `name`, `code`, or `floorId` -> `400` / `房间名称、编号和楼层不能为空`.
|
||||
- Invalid supplied `capacity` -> `400` / `房间容量需为正整数`.
|
||||
- `floorId` not found in active organization -> `404` / `楼层不存在`.
|
||||
- Insert returning no row -> `500` / `房间创建失败`.
|
||||
|
||||
### 5. Good/Base/Bad Cases
|
||||
|
||||
- Good: create UI first exposes real campus/building/floor selection, then submits the selected `floorId`.
|
||||
- Base: if facility hierarchy management is not exposed yet, keep room creation UI hidden or disabled.
|
||||
- Bad: auto-create `"默认院区"`, `"默认楼栋"`, or `"默认楼层"` inside the room API.
|
||||
|
||||
### 6. Tests Required
|
||||
|
||||
- `pnpm lint`
|
||||
- `pnpm type-check`
|
||||
- `pnpm build`
|
||||
- Integration assertions:
|
||||
- missing `floorId` returns `400`
|
||||
- unknown or cross-organization `floorId` returns `404`
|
||||
- valid `floorId` creates a room without inserting campus/building/floor rows
|
||||
|
||||
### 7. Wrong vs Correct
|
||||
|
||||
#### Wrong
|
||||
|
||||
```ts
|
||||
const floor = existingFloor ?? await transaction.insert(floors).values({ name: "默认楼层" }).returning();
|
||||
await transaction.insert(rooms).values({ floorId: floor.id, name, code });
|
||||
```
|
||||
|
||||
#### Correct
|
||||
|
||||
```ts
|
||||
const floorRows = await database
|
||||
.select({ id: floors.id })
|
||||
.from(floors)
|
||||
.where(and(eq(floors.id, floorId), eq(floors.organizationId, organizationId)))
|
||||
.limit(1);
|
||||
const floor = floorRows[0];
|
||||
if (!floor) {
|
||||
return jsonFailure("楼层不存在", 404);
|
||||
}
|
||||
await database.insert(rooms).values({ organizationId, floorId: floor.id, name, code });
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user