SAM AI Page Builder - Architecture Documentation
SAM AI Page Builder - Architecture Documentation
System Overview
┌─────────────────────────────────────────────────────────────────┐
│ Odoo 18 Backend │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ sam.ai.page Model │ │
│ │ • name, description │ │
│ │ • page_html, page_css, page_js │ │
│ │ • ai_prompt_history (JSON) │ │
│ │ • state (draft/generated/published) │ │
│ │ • Methods: add_prompt_to_history(), get_prompt_history() │ │
│ └───────────────────────────────────────────────────────────┘ │
│ ↕ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ XML Views & Menus │ │
│ │ • Tree View (list of pages) │ │
│ │ • Form View (page details) │ │
│ │ • Search View (filters) │ │
│ │ • Client Action (builder interface) │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
↕
┌─────────────────────────────────────────────────────────────────┐
│ Odoo Web Client (OWL 2) │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ AIPageBuilderAction (Main) │ │
│ │ • Loads page data │ │
│ │ • Orchestrates components │ │
│ │ • Handles save/close │ │
│ └───────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────────────┐ ┌──────────────────────────────────┐ │
│ │ SplitLayout │ │ Services │ │
│ │ • Resizable panels │ │ • aiStubService │ │
│ │ • Drag handling │ │ - generatePage() │ │
│ └──────────────────────┘ │ - refinePage() │ │
│ ↓ └──────────────────────────────────┘ │
│ ┌──────────────────────┐ ┌──────────────────────────────────┐ │
│ │ ChatPanel │ │ PageBuilderPanel │ │
│ │ • Message history │ │ • Preview iframe │ │
│ │ • Prompt input │ │ • Code tabs (HTML/CSS/JS) │ │
│ │ • AI interaction │ │ • Zoom, save, export │ │
│ └──────────────────────┘ └──────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Component Architecture
1. Backend Layer (Python)
# models/sam_ai_page.py
class SamAiPage(models.Model):
_name = 'sam.ai.page'
# Data Fields
name = fields.Char()
page_html = fields.Text()
page_css = fields.Text()
page_js = fields.Text()
ai_prompt_history = fields.Text() # JSON
state = fields.Selection()
# Computed Fields
prompt_count = fields.Integer(compute='_compute_prompt_count')
has_content = fields.Boolean(compute='_compute_has_content')
# Methods
def add_prompt_to_history(prompt, response)
def get_prompt_history()
def action_generate()
Responsibilities:
- Store page data
- Manage AI prompt history
- Handle state transitions
- Provide computed fields
- Enforce data validation
2. View Layer (XML)
<!-- views/sam_ai_page_views.xml -->
<tree> <!-- List of pages -->
<form> <!-- Page details -->
<search> <!-- Filters and search -->
<!-- views/sam_ai_page_menus.xml -->
<menuitem> <!-- Top-level menu -->
<menuitem> <!-- AI Pages submenu -->
Responsibilities:
- Define standard Odoo views
- Create menu structure
- Configure filters and actions
- Register client action
3. Frontend Layer (OWL Components)
Main Action
// views/ai_page_builder_action.js
class AIPageBuilderAction extends Component {
setup() {
// Load page data
// Initialize state
// Setup components
}
onGenerate(content) {
// Handle AI generation
// Update preview
}
onSave(content) {
// Save to database
}
}
Responsibilities:
- Entry point for builder interface
- Load/save page data
- Coordinate components
- Handle navigation
Split Layout Component
// components/split_layout/split_layout.js
class SplitLayout extends Component {
setup() {
// Initialize resizer
// Handle drag events
}
_setupResizer() {
// Mouse down/move/up handlers
// Calculate panel widths
}
}
Responsibilities:
- Render left and right panels
- Handle resizing
- Maintain panel proportions
- Enforce min/max widths
Chat Panel Component
// components/chat_panel/chat_panel.js
class ChatPanel extends Component {
setup() {
// Initialize AI service
// Load message history
}
async onSubmitPrompt(ev) {
// Send to AI service
// Update message history
// Notify parent
}
}
Responsibilities:
- Display message history
- Handle prompt input
- Call AI service
- Show loading states
- Manage conversation flow
Page Builder Panel Component
// components/page_builder_panel/page_builder_panel.js
class PageBuilderPanel extends Component {
setup() {
// Initialize view mode
// Setup iframe
}
updateContent(content) {
// Update preview
// Refresh iframe
}
async onSave() {
// Save to database
}
}
Responsibilities:
- Render preview iframe
- Display code tabs
- Handle zoom controls
- Save content
- Export functionality
4. Service Layer
// services/ai_stub_service.js
class AIStubService {
async generatePage(prompt) {
// Simulate AI call
// Return mock HTML/CSS/JS
}
async refinePage(prompt, currentContent) {
// Simulate refinement
// Return updated content
}
}
Responsibilities:
- Provide AI interface
- Return mock responses (stub)
- Simulate network delay
- Easy to swap for real AI
Data Flow
Page Creation Flow
User clicks "Create"
↓
Odoo creates sam.ai.page record
↓
User clicks "Open Builder"
↓
AIPageBuilderAction loads
↓
Fetches page data from backend
↓
Renders SplitLayout with ChatPanel + PageBuilderPanel
↓
User ready to interact
AI Generation Flow
User types prompt in ChatPanel
↓
User presses Enter
↓
ChatPanel.onSubmitPrompt()
↓
Calls aiStubService.generatePage(prompt)
↓
Service returns { html, css, js }
↓
ChatPanel adds to message history
↓
ChatPanel calls props.onGenerate(content)
↓
AIPageBuilderAction.onGenerate()
↓
Updates state.content
↓
Calls PageBuilderPanel.updateContent()
↓
PageBuilderPanel renders in iframe
↓
User sees preview
Save Flow
User clicks "Save" in PageBuilderPanel
↓
PageBuilderPanel.onSave()
↓
Calls orm.write() with content
↓
Backend updates sam.ai.page record
↓
Sets state = 'generated'
↓
Returns success
↓
Shows notification
↓
Updates lastSaved timestamp
State Management
Component State
Each component manages its own state using useState:
ChatPanel:
state = {
messages: [], // Chat history
currentPrompt: "", // Input value
isGenerating: false, // Loading state
error: null // Error message
}
PageBuilderPanel:
state = {
viewMode: "preview", // preview/html/css/js
content: {}, // HTML/CSS/JS
isSaving: false, // Save in progress
lastSaved: null, // Timestamp
scale: 100 // Preview zoom
}
SplitLayout:
state = {
leftWidth: 40, // Percentage
isDragging: false // Resize in progress
}
Global State
Managed by AIPageBuilderAction:
state = {
pageId: null, // Current page ID
pageName: "", // Page name
content: {}, // Current HTML/CSS/JS
promptHistory: [], // All prompts/responses
isLoading: true // Initial load
}
Communication Patterns
Parent → Child (Props)
// Parent passes data and callbacks
<ChatPanel
pageId={state.pageId}
onGenerate={this.onGenerate.bind(this)}
promptHistory={state.promptHistory}
/>
Child → Parent (Callbacks)
// Child calls parent method
if (this.props.onGenerate) {
this.props.onGenerate({ html, css, js });
}
Component → Service
// Component uses service
this.aiService = useService("aiStubService");
const result = await this.aiService.generatePage(prompt);
Component → Backend
// Component calls ORM
this.orm = useService("orm");
await this.orm.write("sam.ai.page", [id], { page_html: html });
Styling Architecture
CSS Variables (Theme)
:root {
/* Colors */
--sam-primary: #667eea;
--sam-secondary: #764ba2;
/* Backgrounds */
--sam-bg-dark: #1e1e1e;
--sam-bg-medium: #252526;
/* Text */
--sam-text-primary: #cccccc;
/* Effects */
--sam-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
--sam-transition: all 0.2s ease;
}
Component Styles
Each component has its own CSS namespace:
.sam-split-*- Split layout.sam-chat-*- Chat panel.sam-builder-*- Builder panel.sam-ai-page-builder- Main container
Responsive Design
@media (max-width: 768px) {
.sam-split-layout {
flex-direction: column;
}
}
Security Model
Access Control
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sam_ai_page_user,sam.ai.page.user,model_sam_ai_page,base.group_user,1,1,1,1
access_sam_ai_page_public,sam.ai.page.public,model_sam_ai_page,base.group_public,1,0,0,0
Rules:
- Internal users: Full access
- Public users: Read-only
Data Validation
@api.model
def create(self, vals):
# Ensure valid JSON
if 'ai_prompt_history' not in vals:
vals['ai_prompt_history'] = '[]'
return super().create(vals)
def write(self, vals):
# Validate JSON
if 'ai_prompt_history' in vals:
try:
json.loads(vals['ai_prompt_history'])
except:
raise ValidationError('Invalid JSON')
return super().write(vals)
Extension Points
Adding New Features
1. New Model Fields:
# models/sam_ai_page.py
custom_field = fields.Char()
2. New View Modes:
// page_builder_panel.js
setViewMode('custom') {
this.state.viewMode = 'custom';
}
3. New AI Capabilities:
// ai_stub_service.js
async customAIMethod(params) {
// Your logic
}
4. New Components:
// components/custom/custom.js
export class CustomComponent extends Component {
static template = "sam_ai_page_builder.Custom";
}
Performance Considerations
Optimizations
- Lazy Loading: Components load only when needed
- Debouncing: Input events are debounced
- Virtual Scrolling: Long message lists (future)
- Code Splitting: Assets loaded on demand
- Caching: Prompt history cached in memory
Best Practices
- Use
useReffor DOM access (notquerySelector) - Use
useStatefor reactive data - Cleanup in
onWillUnmount - Avoid unnecessary re-renders
- Use CSS transforms for animations
Testing Strategy
Manual Testing
- Installation: Module installs cleanly
- Navigation: Menu and views work
- Creation: Can create pages
- Builder: Interface opens correctly
- AI: Prompts return responses
- Preview: Content renders
- Save: Data persists
- Export: Copy/download works
Future: Automated Testing
# tests/test_sam_ai_page.py
class TestSamAiPage(TransactionCase):
def test_create_page(self):
page = self.env['sam.ai.page'].create({
'name': 'Test Page'
})
self.assertTrue(page.id)
Deployment
Production Checklist
- [ ] Test in staging environment
- [ ] Verify all assets load
- [ ] Check browser compatibility
- [ ] Review access rights
- [ ] Backup database
- [ ] Update documentation
- [ ] Train users
Monitoring
- Odoo logs:
docker-compose logs -f odoo - Browser console: F12 → Console
- Network tab: F12 → Network
- Database queries: Odoo debug mode
Summary
The SAM AI Page Builder uses a clean, layered architecture:
- Backend (Python): Data model and business logic
- Views (XML): Standard Odoo interface
- Components (OWL): Modern reactive UI
- Services (JS): AI and business logic
- Styling (CSS): Modern, themeable design
This architecture is:
- ✅ Modular: Easy to extend
- ✅ Maintainable: Clear separation of concerns
- ✅ Scalable: Ready for growth
- ✅ Testable: Components are isolated
- ✅ Future-proof: Easy to swap AI service
Architecture v1.0 | SAM AI Page Builder for Odoo 18