Before writing any router/handler/middleware code for a new entity, read
docs/crud-endpoints.md in full. It documents, with real examples from
server/routers/aiProvider/ (public) and server/private/routers/alertRule/
(enterprise-only), how this repo structures CRUD endpoints:
- Directory/file layout per entity (
index.ts,types.ts,validation.ts, one file per operation). - The standard handler anatomy (zod parsing, OpenAPI registry, response envelope, error handling).
- Where access-control middleware (
verify<Entity>Access) lives and when it's needed vs. plainverifyOrgAccess. - How to wire up
ActionsEnumentries,verifyUserHasAction, andlogActionAudit. - Which of the four router files (
server/routers/external.ts,server/routers/internal.ts,server/private/routers/external.ts,server/private/routers/internal.ts) to register routes in, and the middleware chain template per HTTP verb. - The repo's non-standard verb convention:
PUT= create,POST= update (backwards from typical REST) — don't "fix" this to standard REST verbs, match the existing convention. - The
#dynamicimport alias, for the rare case of a hook needing different implementations in OSS vs. enterprise builds.
Follow that doc's checklist (§8) step by step rather than improvising a
structure. If the doc and the actual code in aiProvider/alertRule ever
disagree, trust the code and flag the doc as stale.