Extending the Template
Learn where and how to add custom functionality to the Vertical Template.
Extension Point Map
Vertical-Template/
├── src/
│ ├── app/
│ │ ├── api/ 🔌 API Routes
│ │ │ └── [your-route]/ Add new API endpoints
│ │ │ └── route.ts
│ │ │
│ │ └── (presentation)/ 📄 Pages
│ │ └── [your-page]/ Add new pages
│ │ └── page.tsx
│ │
│ ├── eai.config/
│ │ └── tenants/ 🔧 Tenant Configs
│ │ └── [tenant].config.ts Add new tenants
│ │
│ └── components/ 🎨 Components
│ └── [your-component].tsx Add custom components
│
├── packages/client/
│ └── src/
│ ├── components/ 📦 Shared Components
│ │ └── [component]/ Add to client package
│ │
│ └── hooks/ 🪝 Custom Hooks
│ └── use[Hook].ts Add custom hooks
│
└── .claude/skills/ 🤖 AI Skills
└── [skill]/ Add Agent Skills
└── SKILL.md
Quick Reference
| I want to... | Location | Guide |
|---|---|---|
| Add a new page | src/app/(presentation)/[page]/page.tsx | Adding Pages |
| Add an API route | src/app/api/[route]/route.ts | Adding API Routes |
| Create a component | src/components/[component].tsx | Custom Components |
| Add a tenant | src/eai.config/tenants/[tenant].config.ts | First Vertical |
| Use Public API | src/app/api/eai/public/... | Public API Access |
Extension Patterns
1. Config-First Approach
New features should integrate with the config-driven system:
// 1. Create your component
export function MyWidget({ data, onAction }: Props) {
return <div>...</div>;
}
// 2. Register in ComponentRegistry
registry.set('MyWidget', MyWidget);
// 3. Add to tenant config
{
component: 'MyWidget',
priority: 1,
storeBindings: [
{ prop: 'data', storePath: 'mySlice.data' }
],
}
2. Protected Routes
Use middleware for authenticated pages:
// src/middleware.ts
export const config = {
matcher: [
'/dashboard/:path*',
'/api/protected/:path*',
],
};
3. Store Integration
New features should use the Zustand store:
// Read state
const value = useStoreValue('mySlice.property');
// Write state
const setStore = useSetStore();
setStore('mySlice.property', newValue, 'MyComponent');
4. API Proxy Pattern
Backend calls go through the BFF proxy:
// Client-side fetch
const data = await fetch('/api/eai/v3/endpoint', {
credentials: 'include',
});
// Token injected server-side by proxy route
Common Extensions
Adding a Dashboard Widget
- Create component in
src/components/ - Register in ComponentRegistry
- Add to tenant config with
storeBindings - Add store slice if needed
Adding a Settings Page
- Create page at
src/app/(presentation)/settings/page.tsx - Add protected route to middleware
- Create settings form component
- Persist settings to store with
persist: true
Adding an API Integration
- Create API route at
src/app/api/[integration]/route.ts - Handle authentication (session or client credentials)
- Create client-side hook to consume API
- Add to component via store or direct fetch
Code-Adjacent Documentation
Each major directory has a README with local conventions:
src/eai.config/README.md- How to add tenantssrc/components/README.md- Component conventionssrc/app/api/README.md- API route patterns
Next Steps
- Adding Pages - Create new routes
- Adding API Routes - Create backend endpoints
- Custom Components - Build UI components
- Public API Access - Anonymous API access
- Local Package Development - Test package changes locally
CLI & Platform
- EAI CLI:
eai init— Scaffold a new vertical project - EAI CLI:
eai tenant— Create and manage tenants - EAI CLI:
eai types— Generate Object Type definitions - EAI CLI:
eai dev— Start dev server with hot reload - Platform Guide: Object Types — Define your data model
- AI-Assisted Development — Build with Claude Code skills and AI workflows