skills/pimcore-studio-backend-openapi-docs/SKILL.md
Pimcore Studio OpenAPI documentation — translation keys for API docs, Prefix and Tags config classes, PermissionConstants, and mandatory translation string creation for new controllers
npx skillsauth add pimcore/skills pimcore-studio-backend-openapi-docsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The StudioBackendBundle uses a layered architecture: Controllers (HTTP only) -> Services (business logic) -> Hydrators (DTO creation). Events provide extension points. All APIs are OpenAPI-documented.
All OpenAPI description, summary, and tag values use translation keys resolved from translations/studio_api_docs.en.yaml in the bundle. Every new controller MUST have corresponding translation strings.
Namespace: OpenApi\Config\
A final class (not an enum) with @internal and a single typed string constant:
/**
* @internal
*/
final class Prefix
{
public const string BUNDLE = AbstractApiController::PREFIX . '/bundle/data-importer';
}
A backed string enum with @internal and a #[Tag] OpenAPI attribute placed before the PHPDoc block:
#[Tag(
name: Tags::DataImporter->value,
description: 'bundle_tag_data_importer_description',
)]
/**
* @internal
*/
enum Tags: string
{
case DataImporter = 'Bundle Data Importer';
}
#[Tag] attribute self-references (Tags::DataImporter->value) in its name parameter.bundle_tag_{bundle_name}_description.Namespace: Utils\Constants\
A final class with @internal and typed string constants:
/**
* @internal
*/
final class PermissionConstants
{
public const string PLUGIN_DATA_IMPORTER_CONFIG = 'plugin_datahub_config';
public const string PLUGIN_DATA_IMPORTER_PERMISSION_READ = 'plugin_datahub_permission_read';
public const string PLUGIN_DATA_IMPORTER_PERMISSION_UPDATE = 'plugin_datahub_permission_update';
public const string PLUGIN_DATA_IMPORTER_PERMISSION_DELETE = 'plugin_datahub_permission_delete';
public const string PLUGIN_DATA_IMPORTER_ADMIN = 'plugin_datahub_admin';
}
Two-tier permission model:
PLUGIN_DATA_IMPORTER_CONFIG): used in controller #[IsGranted(...)] -- broad "can access the data importer at all" check._PERMISSION_READ, _PERMISSION_UPDATE, _PERMISSION_DELETE): used in service loadConfigurationWithPermission() calls -- fine-grained per-configuration checks.All OpenAPI description, summary, and tag values use translation keys resolved from translations/studio_api_docs.en.yaml in the bundle.
Keys follow the pattern: bundle_{bundle_name}_{domain}_{action}_{suffix}
| Suffix | Usage |
|--------|-------|
| _summary | #[Get] / #[Post] / #[Put] / #[Delete] summary parameter |
| _description | #[Get] / #[Post] etc. description parameter |
| _success_description | #[SuccessResponse] description parameter |
Examples:
# translations/studio_api_docs.en.yaml
bundle_copilot_configuration_get_summary: 'Get configuration by name'
bundle_copilot_configuration_get_description: 'Returns a single copilot configuration by name'
bundle_copilot_configuration_get_success_description: 'Configuration data'
bundle_copilot_configuration_list_summary: 'List all configurations'
bundle_copilot_job_run_list_summary: 'List all job runs'
bundle_tag_copilot_description: 'Copilot bundle endpoints'
Tag descriptions use: bundle_tag_{bundle_name}_description.
When adding a new controller, you MUST also add the corresponding translation strings to translations/studio_api_docs.en.yaml. Every operationId, description, summary, and #[SuccessResponse] description value used in OpenAPI attributes is a translation key that must have a matching entry in the YAML file. Forgetting to add these results in raw translation keys being displayed in the OpenAPI documentation instead of human-readable text.
Checklist for each new controller:
{operationId}_description -- describes what the endpoint does (use YAML | for multi-line){operationId}_summary -- short one-line summary{success_response_key} -- the key used in #[SuccessResponse(description: '...')]Example for a new TreeController:
class_field_collection_get_tree_description: |
Get the field collection tree with grouped folders.
class_field_collection_get_tree_summary: Get field collection tree
class_field_collection_get_tree_success_response: Field collection tree with nodes and folders
tools
UX and UI design conventions for Pimcore Studio - layout, spacing, action labels, writing style, and design principles for consistent extensions
tools
Widget system in Pimcore Studio UI - registering widgets, opening them in layout areas, WidgetManagerTabConfig, and connecting widgets to navigation
tools
How bundles consume the Pimcore Studio UI SDK - plugins, modules, DI, registries, and imports
development
TypeScript coding standards and best practices for Pimcore Studio UI - type safety, null checks, and code quality