Cartble’s plugin system is built around a small set of architectural rules that keep each plugin self-contained, visually consistent with the admin, and safe from cross-platform data collisions. Following these patterns ensures your plugin feels like a native part of the platform from day one, and that it remains maintainable as the codebase evolves.Documentation Index
Fetch the complete documentation index at: https://help.cartble.com/llms.txt
Use this file to discover all available pages before exploring further.
The plugin system is designed exclusively for admin-side extensions. Plugins add pages, sidebar navigation, and UI slots inside the Cartble admin shell. They do not modify the customer-facing storefront or the public checkout experience.
Modularity principle
Every plugin is a fully self-contained directory undersrc/plugins/[plugin-name]/. All code that belongs to a plugin — pages, hooks, services, types, utilities, and local components — lives inside that directory. Plugins must not import from each other’s directories, and they must not modify files outside their own scope.
This rule enforces clear ownership: if something is inside src/plugins/your-plugin/, it belongs to that plugin. If it is outside, the plugin should consume it as a shared resource (UI components, hooks) rather than duplicating it.
UI consistency
Your plugin’s UI should be indistinguishable from the rest of the Cartble admin. Follow these rules to achieve that consistency.Use shared UI components
Do not create custom buttons, inputs, or modal dialogs. If an equivalent component already exists insrc/components/ui/, use it.
| Need | Use |
|---|---|
| Buttons | src/components/ui/Button.tsx |
| Text inputs | src/components/ui/Input.tsx |
| Confirmation dialogs | src/components/ui/ConfirmModal.tsx |
Match the admin design system
Apply the same Tailwind CSS color palette, spacing scale, border radius conventions, and typography that the main admin uses. Do not introduce custom color variables or override global styles. Reference existing admin pages to understand which Tailwind classes are standard.Format all prices with formatPrice
Every monetary value your plugin displays must be formatted using formatPrice from the useTranslation hook. This function applies the correct currency symbol and regional number formatting for the platform’s locale. Raw number output or custom formatting functions will produce inconsistent results across locales.
Firestore data model
Cartble’s Firestore database is organized around a platform-scoped hierarchy. Every document your plugin reads or writes must live under theplatforms/{platformId}/ path. Access outside this scope is not permitted.
Collection conventions
| Data type | Firestore path | When to use |
|---|---|---|
| Products and primary assets | platforms/{platformId}/resources/ | When your plugin reads or updates product catalog entries |
| Orders, transactions, and logs | platforms/{platformId}/records/ | When your plugin records financial or operational events |
| Plugin-private data | platforms/{platformId}/[plugin_name]_data/ | For data that only your plugin reads and writes |
resources collection, your documents must conform to the platform’s existing resource schema. Do not add fields that conflict with or shadow existing resource properties.
Platform awareness
All data access must be scoped to the platform the current admin session belongs to. Use theusePlatform() hook to retrieve the platformId and any platform-level settings at runtime. Never construct a Firestore path using a hardcoded string.
React Query patterns
Use React Query as the standard for managing server-side state in your plugin. Your plugin’swithBridge HOC must provide its own QueryClient instance so that the plugin’s cache is entirely isolated from the main application.
Always include platformId as the first element of every query key. This prevents stale data from one platform appearing in another platform’s admin when a user switches accounts within the same session.
Plugin type system
Plugins are defined using thePlugin interface from src/plugins/core/types.ts. The key fields you will work with are:
adminApps for every page your plugin exposes. Each entry requires a unique id, a display label, a Lucide icon, and a component wrapped with your withBridge HOC.