--- name: strapi-cms description: "Strapi content types, custom controllers and services, lifecycle hooks, and REST/GraphQL APIs. Use when changing a Strapi content model, extending its API, or building a Strapi plugin." --- # Strapi CMS Project config, content types, and deployment details: `.opencastle/stack/cms-config.md`. Docs: https://docs.strapi.io/ ## File placement is load-bearing Strapi discovers code by path — a correct file in the wrong place is simply ignored. - `src/api//content-types//schema.json` — content type (or use Content-Type Builder, then commit the generated schema) - `src/api//controllers/.js` — thin wrapper, wraps `createCoreController('api::.', ({ strapi }) => ({ ... }))`; call `super.find(ctx)` then modify the response - `src/api//services/` — all business logic - `src/api//content-types//lifecycles.js` — `beforeCreate`/`afterUpdate` side effects, mutating `event.params.data` - `src/api//graphql/` — custom resolvers - `config/env//` — per-environment config; `config/plugins.ts` registers plugins ## Query gotchas - **Relations are not returned unless requested.** `?populate=author,categories`, or `?populate=deep` for everything. - Filters need an operator: `?filters[status][$eq]=published&filters[views][$gte]=100`. Operators include `$eq`, `$contains`, `$in`, `$gte`. - Field selection is indexed: `?fields[0]=title&fields[1]=slug`. - Pagination: `?pagination[page]=1&pagination[pageSize]=10`. - **New endpoints return 403 until permissions are granted** per role in Users & Permissions — this is the most common "my API is broken" cause. - GraphQL is opt-in via `@strapi/plugin-graphql`; it auto-generates types and resolvers from content types with `filters`/`pagination`/`sort` args. - Plugins: `strapi generate plugin ` → `admin/`, `server/`, `content-types/`. Keep server logic in `server/` so admin code is not bundled into the server build. ## Verify the `develop` script, confirm the type appears in admin, create a test entry, then assert `GET /api/?pagination[page]=1` returns 200 with a `data` array and `GET /api/?populate=*` returns the expected relations. Schema errors surface under the `build` script.