Create a Frontend Plugin
AI prompt to generate a complete frontend-only NaaP plugin with UI, routing, and shell integration.
When to Use This#
Use this prompt when you want to build a UI-only plugin that:
- Displays information or dashboards
- Interacts with external APIs (via the shell's API proxy)
- Doesn't need its own backend server or database
- Is the simplest type of plugin to start with
The Prompt#
Copy the entire block below and paste it into your AI assistant:
| 1 | # Task: Create a NaaP Frontend-Only Plugin |
| 2 | |
| 3 | ## Context: NaaP Platform |
| 4 | |
| 5 | NaaP (Network as a Platform) is a plugin-based platform. Plugins are built as |
| 6 | React applications bundled in UMD format and loaded into a shell application. |
| 7 | |
| 8 | Key technical details: |
| 9 | - Frontend: React 18+, TypeScript, Tailwind CSS, Vite |
| 10 | - Bundle format: UMD (via vite.config.ts using createPluginConfig from @naap/plugin-build/vite) |
| 11 | - Shell integration: @naap/plugin-sdk provides hooks and components |
| 12 | - The shell handles authentication, theming, notifications, and routing |
| 13 | - Deployment: Vercel (production) — plugins are UMD bundles served from same origin |
| 14 | |
| 15 | **CRITICAL — Deployment-Safe API Patterns:** |
| 16 | - NEVER hardcode `http://localhost:PORT` in frontend code |
| 17 | - NEVER use `window.location.hostname + ':PORT'` for API URLs |
| 18 | - NEVER import or reference port numbers directly — `plugin.json → backend.devPort` is the single source of truth for ports; the SDK resolves them for you |
| 19 | - ALWAYS use one of these two SDK functions: |
| 20 | - `getPluginBackendUrl(name, { apiPath })` — returns a prefix you append relative paths to (e.g., `/posts`) |
| 21 | - `getServiceOrigin(name)` — returns just the origin; use when you build full paths (e.g., `/api/v1/registry/packages`) |
| 22 | - For pre-built clients, use `createShellApiClient()` or `createIntegrationClient()` from `@naap/plugin-sdk` — they use `getServiceOrigin('base')` internally |
| 23 | - On Vercel, there are NO separate backend ports — all API traffic is same-origin via relative paths (`/api/v1/...`) |
| 24 | - NEVER call `getPluginBackendUrl('base')` and then append `/api/v1/...` — this creates doubled URLs in production |
| 25 | |
| 26 | **CRITICAL — Build Configuration:** |
| 27 | - Use `createPluginConfig()` from `@naap/plugin-build/vite` for vite.config.ts |
| 28 | - Do NOT add a `postcss.config.js` — PostCSS is configured in the shared Vite config |
| 29 | - Keep a `tailwind.config.js` in your frontend directory (it IS needed) |
| 30 | |
| 31 | Available SDK hooks (import from @naap/plugin-sdk): |
| 32 | - useAuth() → { user, token, hasRole(role), hasPermission(perm) } |
| 33 | - useNotify() → { success(msg), error(msg), warning(msg), info(msg) } |
| 34 | - usePluginApi() → { get(url), post(url, data), put(url, data), delete(url) } |
| 35 | - useThemeService() → { theme, isDark } |
| 36 | - useEvents() → { emit(event, data), on(event, callback), off(event, callback) } |
| 37 | - usePluginContext() → { pluginId, teamId, config } |
| 38 | |
| 39 | Mount function pattern (frontend/src/mount.tsx): |
| 40 | ```tsx |
| 41 | import { createRoot } from 'react-dom/client'; |
| 42 | import { ShellProvider } from '@naap/plugin-sdk'; |
| 43 | import App from './App'; |
| 44 | |
| 45 | export function mount(container: HTMLElement, shellContext: any) { |
| 46 | const root = createRoot(container); |
| 47 | root.render( |
| 48 | <ShellProvider context={shellContext}> |
| 49 | <App /> |
| 50 | </ShellProvider> |
| 51 | ); |
| 52 | return () => root.unmount(); |
| 53 | } |
Requirements#
Create a frontend-only NaaP plugin called "[YOUR_PLUGIN_NAME]" that does:
[DESCRIBE WHAT YOUR PLUGIN SHOULD DO HERE — for example:
- "A bookmark manager that lets users save and organize links"
- "A weather dashboard that shows current weather for cities"
- "A Pomodoro timer with task tracking"
- "A team announcement board" ]
Technical Specifications#
-
Generate a complete plugin.json manifest:
JSON1 { 2 "name": "[plugin-name]", 3 "displayName": "[Plugin Display Name]", 4 "version": "1.0.0", 5 "description": "[description]", 6 "category": "[pick: analytics|communication|developer-tools|finance|infrastructure|monitoring|other]", 7 "author": { "name": "[Your Name]" }, 8 "frontend": { 9 "entry": "production/[plugin-name].js", 10 "routes": [{ "path": "/[plugin-name]", "component": "App" }], 11 "navigation": { 12 "label": "[Display Name]", 13 "icon": "[lucide-icon-name]", 14 "order": 50 15 } 16 }, 17 "permissions": ["read:profile"] 18 } -
Generate the full file structure:
1 [plugin-name]/ 2 ├── plugin.json 3 ├── frontend/ 4 │ ├── package.json (react, @naap/plugin-sdk, tailwindcss, vite deps) 5 │ ├── tsconfig.json 6 │ ├── vite.config.ts (UMD build config via createPluginConfig) 7 │ ├── tailwind.config.js (content paths & theme extensions) 8 │ ├── src/ 9 │ │ ├── App.tsx (main component with routing/layout) 10 │ │ ├── mount.tsx (shell mount function) 11 │ │ └── components/ (reusable UI components) 12 │ └── index.html Do NOT include:
postcss.config.js(PostCSS is configured in the shared Vite config) -
Use Tailwind CSS for all styling. Make the UI look professional and modern.
-
Use the useAuth() hook to show user-specific content.
-
Use the useNotify() hook for success/error feedback.
-
Use the usePluginApi() hook if the plugin needs to fetch external data.
-
If you need a direct API URL (outside React), use getPluginBackendUrl() — NEVER hardcode localhost:port.
-
Include proper loading states, error handling, and empty states.
-
Make the UI responsive (mobile + desktop).
Quality Standards#
- All TypeScript — no
anytypes - Components are modular and reusable
- Include helpful code comments
- Follow React best practices (proper state management, effect cleanup)
- Handle edge cases (loading, errors, empty data)
Generate ALL files with complete, working code. Do not use placeholders.
| 1 | |
| 2 | ## How to Customize |
| 3 | |
| 4 | Before pasting, replace these sections: |
| 5 | |
| 6 | 1. **`[YOUR_PLUGIN_NAME]`** — your plugin's name (e.g., `bookmark-manager`) |
| 7 | 2. **`[DESCRIBE WHAT YOUR PLUGIN SHOULD DO]`** — write 2-3 sentences about what the plugin does |
| 8 | 3. **`[Your Name]`** — your name for the author field |
| 9 | |
| 10 | ## After the AI Generates Code |
| 11 | |
| 12 | ```bash |
| 13 | # 1. Create the plugin directory |
| 14 | naap-plugin create my-plugin --template frontend-only |
| 15 | |
| 16 | # 2. Replace the generated files with the AI's output |
| 17 | # (copy each file the AI generated into the right location) |
| 18 | |
| 19 | # 3. Install dependencies |
| 20 | cd my-plugin/frontend |
| 21 | npm install |
| 22 | |
| 23 | # 4. Start the dev server |
| 24 | naap-plugin dev |
| 25 | |
| 26 | # 5. Open http://localhost:3000 — your plugin appears in the sidebar |
Example: Bookmark Manager#
Here's a filled-in version of the requirements section:
| 1 | Create a frontend-only NaaP plugin called "bookmark-manager" that does: |
| 2 | |
| 3 | - Lets users save URLs with a title, description, and tags |
| 4 | - Organizes bookmarks into folders/categories |
| 5 | - Has a search bar to filter bookmarks by title or tag |
| 6 | - Shows a grid view and a list view (toggle between them) |
| 7 | - Uses localStorage to persist bookmarks (no backend needed) |
| 8 | - Has an "import/export" feature to backup bookmarks as JSON |
| 9 | - Shows a count of total bookmarks and most-used tags |
Follow-Up Prompts#
After the initial plugin is generated, you can refine it:
| 1 | # Add drag-and-drop reordering to the bookmark list |
| 2 | # Use react-beautiful-dnd or a similar library |
| 3 | |
| 4 | Add drag-and-drop functionality so users can reorder their bookmarks |
| 5 | by dragging them. Keep the existing grid/list toggle working. |
| 1 | # Make the UI more polished |
| 2 | Improve the visual design of the bookmark manager: |
| 3 | - Add subtle animations when adding/removing bookmarks |
| 4 | - Use a card-based layout with hover effects |
| 5 | - Add a dark mode that follows the shell theme (useThemeService) |
| 6 | - Add favicon previews for each bookmarked URL |