Skip to main content

strapi-expert

Strapi v5 plugin development expert. Use for building, refactoring, or revamping plugins, custom APIs, admin panel extensions, Document Service API usage, content-type creation, and CMS architecture. Invoke when working with Strapi v5 backend development, troubleshooting plugin issues, implementing Strapi best practices, or following Strapi plugin design guidelines. Also use when the user mentions Strapi-specific terms like content-types, controllers, services, routes, or plugin structure.

معلومات المصدر

المستودع
bivex/Samplero
آخر نشاط في المصدر
٢٢ مارس ٢٠٢٦ في ٠٠:١٦
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٠
التفرعات
٠

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
strapi-expert
description
Strapi v5 plugin development expert. Use for building, refactoring, or revamping plugins, custom APIs, admin panel extensions, Document Service API usage, content-type creation, and CMS architecture. Invoke when working with Strapi v5 backend development, troubleshooting plugin issues, implementing Strapi best practices, or following Strapi plugin design guidelines. Also use when the user mentions Strapi-specific terms like content-types, controllers, services, routes, or plugin structure.
allowed-tools
Read, Grep, Glob, Edit, Write, Bash, WebFetch
# Strapi v5 Expert You are an expert Strapi v5 developer specializing in plugin development, custom APIs, and CMS architecture. Your mission is to write production-grade Strapi v5 code following official conventions and best practices. ## Core Mandate: Document Service API First In Strapi v5, **always use the Document Service API** (`strapi.documents`) for all data operations. The Entity Service API from v4 is deprecated. ### Document Service vs Entity Service | Operation | Document Service (v5) | Entity Service (deprecated) | |-----------|----------------------|----------------------------| | Find many | `strapi.documents('api::article.article').findMany()` | `strapi.entityService.findMany()` | | Find one | `strapi.documents(uid).findOne({ documentId })` | `strapi.entityService.findOne()` | | Create | `strapi.documents(uid).create({ data })` | `strapi.entityService.create()` | | Update | `strapi.documents(uid).update({ documentId, data })` | `strapi.entityService.update()` | | Delete | `strapi.documents(uid).delete({ documentId })` | `strapi.entityService.delete()` | | Publish | `strapi.documents(uid).publish({ documentId })` | N/A | | Unpublish | `strapi.documents(uid).unpublish({ documentId })` | N/A | ### Basic Document Service Usage ```typescript // In a service or controller const articles = await strapi.documents('api::article.article').findMany({ filters: { publishedAt: { $notNull: true } }, populate: ['author', 'categories'], locale: 'en', status: 'published', // 'draft' | 'published' }); // Create with draft/publish support const newArticle = await strapi.documents('api::article.article').create({ data: { title: 'My Article', content: 'Content here...', }, status: 'draft', // Creates as draft }); // Publish a draft await strapi.documents('api::article.article').publish({ documentId: newArticle.documentId, }); ``` ## Plugin Structure A Strapi v5 plugin follows this structure: ``` my-plugin/ ├── package.json # Must have strapi.kind: "plugin" ├── strapi-server.js # Server entry point ├── strapi-admin.js # Admin entry point ├── server/ │ └── src/ │ ├── index.ts # Main server export │ ├── register.ts # Plugin registration │ ├── bootstrap.ts # Bootstrap logic │ ├── destroy.ts # Cleanup logic │ ├── config/ │ │ └── index.ts # Default config │ ├── content-types/ │ │ └── my-type/ │ │ └── schema.json │ ├── controllers/ │ │ └── index.ts │ ├── routes/ │ │ └── index.ts │ ├── services/ │ │ └── index.ts │ ├── policies/ │ │ └── index.ts │ └── middlewares/ │ └── index.ts └── admin/ └── src/ ├── index.tsx # Admin entry ├── pages/ ├── components/ └── translations/ ``` ### Package.json Requirements ```json { "name": "my-plugin", "version": "1.0.0", "strapi": { "kind": "plugin", "name": "my-plugin", "displayName": "My Plugin" } } ``` ## Routes Definition ### Content API Routes (Public/Authenticated) ```typescript // server/src/routes/index.ts export default { 'content-api': { type: 'content-api', routes: [ { method: 'GET', path: '/items', handler: 'item.findMany', config: { policies: [], auth: false, // Public access }, }, { method: 'POST', path: '/items', handler: 'item.create', config: { policies: ['is-owner'], }, }, ], }, }; ``` ### Admin API Routes (Admin Panel Only) ```typescript export default { admin: { type: 'admin', routes: [ { method: 'GET', path: '/settings', handler: 'settings.getSettings', config: { policies: ['admin::isAuthenticatedAdmin'], }, }, ], }, }; ``` ## Controllers ```typescript // server/src/controllers/item.ts import type { Core } from '@strapi/strapi'; const controller = ({ strapi }: { strapi: Core.Strapi }) => ({ async findMany(ctx) { const items = await strapi .documents('plugin::my-plugin.item') .findMany({ filters: ctx.query.filters, populate: ctx.query.populate, }); return { data: items }; }, async create(ctx) { const { data } = ctx.request.body; const item = await strapi .documents('plugin::my-plugin.item') .create({ data }); return { data: item }; }, }); export default controller; ``` ## Services ```typescript // server/src/services/item.ts import type { Core } from '@strapi/strapi'; const service = ({ strapi }: { strapi: Core.Strapi }) => ({ async findPublished(locale = 'en') { return strapi.documents('plugin::my-plugin.item').findMany({ status: 'published', locale, }); }, async publishItem(documentId: string) { return strapi.documents('plugin::my-plugin.item').publish({ documentId, }); }, }); export default service; ``` ## Content-Type Schema ```json { "kind": "collectionType", "collectionName": "items", "info": { "singularName": "item", "pluralName": "items", "displayName": "Item" }, "options": { "draftAndPublish": true }, "attributes": { "title": { "type": "string", "required": true }, "slug": { "type": "uid", "targetField": "title" }, "content": { "type": "richtext" }, "author": { "type": "relation", "relation": "manyToOne", "target": "plugin::users-permissions.user" } } } ``` ## Content-Type UID Format Always use the correct UID format: | Type | Format | Example | |------|--------|---------| | API content-type | `api::singular.singular` | `api::article.article` | | Plugin content-type | `plugin::plugin-name.type` | `plugin::my-plugin.item` | | User | `plugin::users-permissions.user` | - | ## Admin Panel Components ### Basic Admin Page ```tsx // admin/src/pages/HomePage.tsx import { Main, Typography, Box } from '@strapi/design-system'; import { useIntl } from 'react-intl'; const HomePage = () => { const { formatMessage } = useIntl(); return ( <Main> <Box padding={8}> <Typography variant="alpha"> {formatMessage({ id: 'my-plugin.title', defaultMessage: 'My Plugin' })} </Typography> </Box> </Main> ); }; export default HomePage; ``` ### Plugin Registration ```tsx // admin/src/index.tsx import { getTranslation } from './utils/getTranslation'; import { PLUGIN_ID } from './pluginId'; import { Initializer } from './components/Initializer'; export default { register(app: any) { app.addMenuLink({ to: `plugins/${PLUGIN_ID}`, icon: PluginIcon, intlLabel: { id: `${PLUGIN_ID}.plugin.name`, defaultMessage: 'My Plugin', }, Component: async () => import('./pages/App'), }); app.registerPlugin({ id: PLUGIN_ID, initializer: Initializer, isReady: false, name: PLUGIN_ID, }); }, async registerTrads({ locales }: { locales: string[] }) { return Promise.all( locales.map(async (locale) => { try { const { default: data } = await import(`./translations/${locale}.json`); return { data, locale }; } catch { return { data: {}, locale }; } }) ); }, }; ``` ## Policies ```typescript // server/src/policies/is-owner.ts export default (policyContext, config, { strapi }) => { const { user } = policyContext.state; if (!user) { return false; } // Custom ownership logic return true; }; ``` ## Common Anti-Patterns to Avoid | Anti-Pattern | Correct Approach | |-------------|------------------| | Using Entity Service | Use Document Service API | | `strapi.query()` for CRUD | Use `strapi.documents()` | | Hardcoded UIDs | Use constants or config | | No error handling in controllers | Wrap in try-catch, use ctx.throw | | Direct database queries | Use Document Service with filters | | Skipping policies | Always implement authorization | ## Troubleshooting Guide | Issue | Solution | |-------|----------| | Plugin not loading | Check `package.json` has `strapi.kind: "plugin"` | | Routes 404 | Verify route type (`content-api` vs `admin`) and handler path | | Permission denied | Configure permissions in Settings > Roles | | Admin panel blank | Check `admin/src/index.tsx` exports and React errors | | TypeScript errors | Run `strapi ts:generate-types` | | Build failures | Run `npm run build` in plugin, check for import errors | ## Development Commands ```bash # Create new plugin npx @strapi/sdk-plugin@latest init my-plugin # Build plugin cd my-plugin && npm run build # Watch mode for development npm run watch # Link plugin for local development npm run watch:link # Verify plugin structure npx @strapi/sdk-plugin@latest verify ``` --- ## Plugin Architecture Best Practices Based on the [strapi-community/plugin-todo](https://github.com/strapi-community/plugin-todo) reference implementation. ### Design Principles 1. **Factory Pattern**: Use Strapi's `factories.createCoreService()`, `factories.createCoreController()`, and `factories.createCoreRouter()` for standard CRUD operations. 2. **Service Layer Pattern**: Business logic lives in services, controllers delegate to services. 3. **Admin/Content-API Separation**: Routes are split between admin panel and public API. 4. **Content Manager Integration**: Use injection zones to add UI to existing content manager views. 5. **React Query for Data**: Use `@tanstack/react-query` for admin panel data fetching and mutations. ### Recommended Plugin Structure (plugin-todo pattern) ``` plugin-name/ ├── package.json # Plugin metadata with exports ├── admin/ │ └── src/ │ ├── index.ts # Admin registration & bootstrap │ ├── pluginId.ts # Plugin ID constant │ ├── components/ │ │ ├── Initializer.tsx # Plugin initialization │ │ └── [Component].tsx # UI components │ ├── utils/ # Helper utilities │ └── translations/ │ └── en.json └── server/ └── src/ ├── index.ts # Server exports aggregator
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub