Files
trackgo-be/.cursor/rules/read-write-controllers.mdc
T
shancheas 4c45a4371e Enhance pagination and ordering capabilities in API responses
- Updated pagination-response and read-write-controllers documentation to include `orderBy` and `orderType` parameters for sorting results.
- Introduced new `order-clause` module to handle ordering logic, including validation for order types and columns.
- Enhanced `PaginationQueryDto` to support ordering fields in API requests.
- Updated various repository and service classes to implement ordering in database queries.
- Added unit tests for new ordering functionality and ensured existing tests cover the updated behavior.
- Refactored related DTOs to include user and code relations for better data representation in responses.
2026-08-27 13:09:41 +07:00

57 lines
2.6 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
description: Main modules use separate read and write controllers with list/detail, CRUD, status, bulk, and CSV import
globs: "src/modules/**/*.ts"
alwaysApply: false
---
# Read / Write Controllers
## Structure
Every **main** (CRUD) feature module under `src/modules/` MUST expose at least:
- `*-read.controller.ts`
- `*-write.controller.ts`
Same resource path and `@ApiTags`. Example: `@Controller('shipments')`.
Exempt: auth and similar non-CRUD modules (single controller is fine).
```typescript
@Module({
controllers: [ShipmentsReadController, ShipmentsWriteController],
providers: [ShipmentsService, ShipmentsRepository],
})
export class ShipmentsModule {}
```
Register static write paths (`import`, `bulk-delete`, `bulk-status`) **before** parameterized `:id` routes so they never collide.
## Read controller
1. `GET /` — list
2. `GET /:id` — detail
List requirements:
- Query filters for the resources own attributes **plus** `search` (case-insensitive match on the modules searchable text columns; AND with other filters)
- Shared pagination query (`page`/`limit` or `offset`/`limit`) plus `orderBy`/`orderType` via `PaginationQueryDto`
- Handler **must** use `@Pagination()` and return `{ data, total }` — never build `meta` here (see `.cursor/rules/pagination-response.mdc`)
- Service `visibleFields` whitelist: default **all non-secret** attributes; modules may narrow. Project in the **service**, not the controller
- FK relations in list/detail (and write responses that reuse the mapper) MUST be nested objects via `pickRelation` — see `.cursor/rules/relation-response.mdc`
- List query must be extendable (e.g. `extendListQuery(qb, filters)` on the repository/service) so joins/extra predicates can be added without forking list
## Write controller
1. `POST /` — create (status defaults to `draft` unless body sets a valid status)
2. `PATCH /:id` — update (**must not** change `status`; reject if `status` is present)
3. `DELETE /:id` — delete (hard delete unless the module documents otherwise)
4. `PATCH /:id/status` — body is **only** `{ status }`
5. `POST /bulk-delete` — `{ ids: string[] }`
6. `POST /bulk-status` — `{ ids: string[], status }`
7. `POST /import` — multipart CSV `file`; headers map to create fields; omitted status → `draft`; `created_by` / `updated_by` = current user; fail the batch on validation errors with row-level messages (do not echo raw invalid phones/dates beyond VO policy)
Set `created_at` / `updated_at` (`DateTime`) and `created_by` / `updated_by` (current user id) in the write path.
Document both controllers per `.cursor/rules/nestjs-swagger.mdc`.