feat: add opencode skill for tx-admin-endpoint collection and API generation
This commit is contained in:
@@ -0,0 +1,86 @@
|
|||||||
|
---
|
||||||
|
name: tx-admin-endpoint
|
||||||
|
description: "Trigger: crear colección, nueva colección, crear endpoint, nuevo endpoint, Models, api, turnosxpress admin. Reglas para crear colecciones y endpoints del backend admin de turnosxpress."
|
||||||
|
license: Apache-2.0
|
||||||
|
metadata:
|
||||||
|
author: gentleman-programming
|
||||||
|
version: "1.0"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Activation Contract
|
||||||
|
|
||||||
|
Load this skill when creating a new collection or a new endpoint in the `server` backend of the turnosxpress admin (the API consumed by admins/employees, not the public client app). Applies to both the data layer (`server/src/Models`) and the HTTP layer (`server/src/api`). Example to imitate: `Clients`, `Posts`, `SchedulesDisabled`.
|
||||||
|
|
||||||
|
## Hard Rules
|
||||||
|
|
||||||
|
- Use the ACTUAL paths: collections live in `server/src/Models/<Name>/`, endpoints in `server/src/api/<Name>/`. The folder name is the collection name (e.g. `Clients`, `Posts`).
|
||||||
|
- A collection is ALWAYS exactly 3 files with separated responsibilities (never collapse them):
|
||||||
|
|
||||||
|
| File | Owns | Forbidden here |
|
||||||
|
|------|------|-----------------|
|
||||||
|
| `<Name>.Interface.ts` | All TS types: `*Params` (Create/Update/Delete/Find), `IX`, `IXDocument` re-export, `IXAdapter`, `IXManager`, view/result types. | No Mongoose, no business logic. |
|
||||||
|
| `<Name>.Adapter.Mongoose.ts` | Mongoose ONLY: `Schema`, `IXDocument extends IX & Document`, `model()`, and pure DB ops (`create`, `delete`, `find`, `findOne`, `paginate`). Implements `IXAdapter`. | No business rules, NO security checks. |
|
||||||
|
| `<Name>.ts` | Business rules AND security. A `<Name>Manager implements IXManager` class that instantiates the adapter in the constructor; exported as a singleton (`const XList = new ...Manager(); export default XList;`). | No Schema, no `model()`. |
|
||||||
|
|
||||||
|
- SECURITY STANDARD (mandatory, even though `Clients.ts` inlines it — that is legacy): use the shared helpers from `server/src/helpers/check.ts`:
|
||||||
|
- `validateSessionUser({ sessionUser })` — confirm the session user exists. Call FIRST in any method that receives `sessionUser`.
|
||||||
|
- `validatePermissionsByCompany({ companyId, sessionUser })` — confirm the company exists AND the session user has ADMIN role. Call whenever a `companyId` is involved.
|
||||||
|
- Modern reference: `server/src/Models/Posts/Posts.ts`, `server/src/Models/SchedulesDisabled/SchedulesDisabled.ts`.
|
||||||
|
- Role checks beyond ADMIN (EMPLOYEE, etc.) go through `EmployeesList.checkPermission` / `checkRoleById`.
|
||||||
|
- An endpoint is ALWAYS 2 files:
|
||||||
|
- `<Name>.Controller.ts` — tsoa decorators. One controller class per `@Route("resource/action")`. Each handler `@Post()`, takes `@Body()`, sets status, wraps in try/catch and returns `new ApiValidationError(500, message)` on error. Import `ApiValidationError` from `../../Models/Server.Error.model`.
|
||||||
|
- `<Name>.Service.ts` — thin: each method `await connect(process.env.DATABASE_CONNECTION)` then delegates to the manager singleton. No business logic here.
|
||||||
|
- `authenticationMiddleware` (from `server/src/middleware/authentication.ts`) MUST be applied with `@Middlewares(authenticateMiddleware)` on EVERY controller, UNLESS the endpoint is intentionally public. Never omit it without explicit confirmation (see Ask Before Building).
|
||||||
|
- 99% of endpoints use `@Post()`. Default to POST; use GET/other only with a concrete, justified reason.
|
||||||
|
- After adding/changing controllers, regenerate the tsoa routes/spec: `npm run routes` (binds `tsoa spec-and-routes`); compile with `npm run build`.
|
||||||
|
|
||||||
|
## Decision Gates
|
||||||
|
|
||||||
|
| Situation | Decision |
|
||||||
|
|-----------|----------|
|
||||||
|
| Does the method take `sessionUser`? | Call `validateSessionUser` first. |
|
||||||
|
| Does the method act on a `companyId`? | Then `validatePermissionsByCompany`. |
|
||||||
|
| Endpoint exposed in the admin backend? | Default: `@Middlewares(authenticateMiddleware)`. |
|
||||||
|
| Endpoint hits WhatsApp notification / public recovery / ratings or another abuse-prone path? | Consider `rateLimiter` (or `ratingRateLimiter`) from `server/src/middleware/ratelimiter.ts`. When both apply: `@Middlewares([rateLimiter, authenticateMiddleware])`. |
|
||||||
|
| Internal/system-only endpoint? | Use `systemTokenMiddleware` instead of/with the above. |
|
||||||
|
| Doubt about middleware, role, or method? | STOP and ask. See Ask Before Building. |
|
||||||
|
|
||||||
|
## Ask Before Building (HARD — security first)
|
||||||
|
|
||||||
|
STOP and ask the user BEFORE writing security or middleware code whenever there is ANY doubt. Never guess on these:
|
||||||
|
|
||||||
|
1. Which validations/roles/plan features the new method requires (ADMIN vs EMPLOYEE vs extra feature gates).
|
||||||
|
2. Whether the endpoint should be public (no `authenticateMiddleware`) or authenticated. A missing auth middleware is a security hole — when unsure, default to KEEPING `authenticateMiddleware` and confirm.
|
||||||
|
3. Whether `rateLimiter` should be applied to a given endpoint. Do NOT add it by default; ask when the endpoint could be abuse-prone.
|
||||||
|
4. Whether a non-POST method is genuinely needed.
|
||||||
|
|
||||||
|
Ask at most a couple of focused questions, then wait. Do not proceed by assumption on security.
|
||||||
|
|
||||||
|
## Execution Steps
|
||||||
|
|
||||||
|
Creating a collection:
|
||||||
|
|
||||||
|
1. Create `server/src/Models/<Name>/<Name>.Interface.ts` — define all params, `IX`, `IXAdapter`, `IXManager`, view/result types.
|
||||||
|
2. Create `server/src/Models/<Name>/<Name>.Adapter.Mongoose.ts` — schema, `IXDocument`, `model()`, pure DB ops implementing `IXAdapter`.
|
||||||
|
3. Create `server/src/Models/<Name>/<Name>.ts` — `<Name>Manager implements IXManager`; instantiate the adapter in the constructor; put business rules; call `validateSessionUser` / `validatePermissionsByCompany` at the top of each secured method; export a singleton default.
|
||||||
|
4. Re-check Ask Before Building for any unconfirmed security requirement.
|
||||||
|
|
||||||
|
Creating an endpoint:
|
||||||
|
|
||||||
|
1. Create `server/src/api/<Name>/<Name>.Service.ts` — one method per action, `connect(process.env.DATABASE_CONNECTION)` then delegate to the manager singleton.
|
||||||
|
2. Create `server/src/api/<Name>/<Name>.Controller.ts` — one controller class per `@Route`; `@Middlewares(authenticateMiddleware)` unless confirmed public; `@Post()` + `@Body()`; try/catch returning `ApiValidationError`.
|
||||||
|
3. Apply Decision Gates (rateLimiter? system token? method?).
|
||||||
|
4. Regenerate routes: `npm run routes` then `npm run build`.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Return: files created, the singletons/middlewares wired, any security decision that was confirmed with the user, and whether `npm run routes` / `npm run build` were run.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- `server/src/Models/Clients/Clients.ts`, `Clients.Interface.ts`, `Clients.Adapter.Mongoose.ts` — canonical 3-file collection example (note: Clients inlines security; do NOT copy that part).
|
||||||
|
- `server/src/Models/Posts/Posts.ts` — modern security pattern using the shared helpers.
|
||||||
|
- `server/src/helpers/check.ts` — `validateSessionUser`, `validatePermissionsByCompany`, `validatePermissionsByClient`.
|
||||||
|
- `server/src/api/Clients/Clients.Controller.ts`, `Clients.Service.ts` — endpoint pattern (Controller + Service).
|
||||||
|
- `server/src/middleware/authentication.ts`, `server/src/middleware/ratelimiter.ts` — middleware sources.
|
||||||
|
- `server/tsoa.json`, `server/package.json` (`npm run routes`) — route generation.
|
||||||
Reference in New Issue
Block a user