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));
|
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