UnoPim Plugin Development
Build a self-contained Concord package under packages/Webkul/{ModuleName}/ — a feature
module or a third-party connector (Shopify, Shopware, any REST API). The living connector
reference is packages/Webkul/AiAgent; when a template here and that package disagree,
the package wins.
Reference files — load only what the current phase needs
| File | Load when |
|---|---|
| quickstart.md | Starting a new module — the day-1 ordered checklist |
| package-structure.md | Directory layout, composer.json, service providers, config merging, migrations |
| backend.md | Models, contracts, repositories, events, Octane-safe bindings |
| credentials.md | Credential storage, encryption at rest, history/audit, test-connection endpoint |
| http-client.md | cURL ApiClient, auth strategies, SSRF guard, container binding |
| admin-ui.md | Blade views — components, theme tokens, CRUD summary |
| crud-patterns.md | The admin CRUD envelope — save bar, modal create, breadcrumbs, page skeleton |
| acl-security.md | ACL coverage, FormRequest authorization, uploads, CSRF, secrets |
| mapping.md | Attribute-mapping screens for a connector |
REQUIRED SUB-SKILL: Use unopim-datagrid for any admin listing page. REQUIRED SUB-SKILL: Use unopim-data-transfer for Exporter, Importer and Validator classes. REQUIRED SUB-SKILL: Use unopim-verify before claiming any change is complete.
Critical conventions (details and exemplars in the reference files)
- Target Laravel 13 / PHP 8.4: promoted constructor properties, explicit return types,
#[Fillable]/#[Table]/#[Hidden]attributes plus acasts(): arraymethod on models. - Providers register in
bootstrap/providers.php—config/app.phphas NO providers array. - Menu config merges into the
'menu.admin'key, NEVER'menu'— the admin sidebar reads onlyconfig('menu.admin'), so a module merged into'menu'never appears. - Plugin packages keep migrations in root-level
Database/Migration/(singular); core packages usesrc/Database/Migrations/(plural). Table names are written bare — the prefix comes fromenv('DB_PREFIX', ''), whose default is EMPTY. - Route middleware is
['admin']only. ACL enforcement is fail-open by route name: every write route (store, update, destroy, mass_*, test-connection) MUST appear inConfig/acl.phpor any logged-in admin can call it. See acl-security.md. - A history/audit model MUST implement its module contract,
PresentableHistoryInterface(withgetPresenters()), and the OwenItAuditablecontract, useHistoryTrait, and define$historyTags— omitting any one is a fatal at class load or on first save. - Secrets at rest need the
'encrypted'cast +#[Hidden]+$auditExcludeTOGETHER.$auditExcludealone stores plaintext. - Connector HTTP is native cURL — never Guzzle, never the
Httpfacade. Stateful clients bindscoped(), neversingleton()(this stack runs Octane). - Localization lives in
Resources/lang/{locale}/withen_UScanonical across 33 locales — a bareen/directory never loads. - NO comments inside method bodies, array literals, route groups or Blade markup. A method PHPDoc is a one-line imperative summary.
- NO hardcoded user-facing strings —
trans('{module}::app.…')for every label, message and placeholder.