Platform Skin Model
SAM AI Platform Skin Architecture Model
π― Executive Summary
SAM AI uses a three-layer architecture where data, framework, and UI are completely separated:
- ai_brain = Pure data layer (ALL models, no views)
- ai_sam = Framework + Canvas core + Controllers (business logic, no data models)
- Platform Skins = UI renderers only (views, JS/CSS, specific to each platform)
ONE data layer (ai_brain) + ONE framework (ai_sam) + MANY skins (platforms) = Infinite extensibility with data safety
π Terminology
Platform Skin:
A Platform Skin is a UI-only module that provides:
- β Views (XML)
- β Frontend code (JavaScript/CSS)
- β Platform-specific renderers
- β Optional: Platform-specific controllers (if needed for UI logic)
- β NO DATA MODELS (all data lives in ai_brain)
Examples:
ai_sam_workflows= Workflow automation skin (N8N-style UI)ai_sam_memory= Knowledge graph visualization skinai_sam_creatives= Multimedia canvas skin
"Debug UI issues 1 platform at a time" - Each skin is independent, uninstalling won't affect data
ποΈ Three-Layer Architecture
π What Goes Where
ai_brain (Data Layer)
Contains:
- β ALL data models (ir.model records)
- β User data (workflows, projects, conversations)
- β Audit trails (executions, token usage)
- β Sensitive data (API credentials, user profiles)
- β Configuration data (settings, templates)
Does NOT contain:
- β Views (no XML files)
- β Controllers (no HTTP endpoints)
- β Frontend code (no JS/CSS)
# ai_brain/models/__init__.py # Core SAM AI models from . import ai_service_config from . import ai_conversation from . import ai_message from . import sam_user_profile # Workflow data (used by ai_sam_workflows skin) from . import canvas # Workflow definitions from . import executions # Execution history from . import nodes # Node instances from . import connections # Node connections from . import api_credentials # API keys # Memory data (used by ai_sam_memory skin) from . import ai_memory_config from . import ai_conversation_import # Creatives data (used by ai_sam_creatives skin) from . import creatives_project from . import creatives_asset
- β Cannot uninstall ai_brain (base dependency)
- β Data protected forever
ai_sam (Framework Layer)
Contains:
- β Canvas Skeleton Core (universal canvas engine)
- β Platform Loader (dynamic skin injection)
- β Universal Services (Claude API, context builder)
- β Universal Controllers (query engines, chat API)
- β Site-wide UI (chat widget, token counter)
Does NOT contain:
- β Data models (belongs in ai_brain)
- β Platform-specific UI (belongs in skins)
ai_sam/
βββ models/ β β SHOULD BE EMPTY (no data models)
βββ controllers/ β β Universal controllers
β βββ canvas_controller.py (canvas API - query engine)
β βββ sam_ai_chat_controller.py (chat endpoints)
β βββ sam_session_controller.py (session management)
β βββ [future query controllers]
βββ static/src/
β βββ core/ β β Canvas skeleton core
β β βββ canvas_sizer.js
β β βββ canvas_engine.js
β β βββ node_manager.js
β β βββ platform_loader.js
β βββ js/ β β Universal UI components
β β βββ sam_ai_chat_widget.js
β β βββ sam_ai_token_counter.js
β βββ css/ β β Universal styles
βββ views/ β β Universal views (menu structure, canvas container)
Controllers in ai_sam (Query Engines):
Controllers in ai_sam are universal query engines that work across all platforms:
# ai_sam/controllers/canvas_controller.py
class CanvasController(http.Controller):
"""
Universal canvas API - works for ALL platforms
Queries ai_brain models, returns data to any skin
"""
@http.route('/sam/canvas/list', type='json', auth='user')
def list_canvases(self, platform=None):
# Query ai_brain.canvas model
# Can filter by platform (workflows, memory, creatives)
Canvas = request.env['canvas']
return Canvas.search_read([...])
@http.route('/sam/canvas/save', type='json', auth='user')
def save_canvas(self, canvas_id, data):
# Save to ai_brain.canvas model
# Works regardless of which skin is using it
Canvas = request.env['canvas']
canvas = Canvas.browse(canvas_id)
canvas.write(data)
return {'success': True}
If 2+ platforms will use it β ai_sam (universal controller)
If only 1 platform uses it β That platform's controller (direct to ai_brain)
This avoids unnecessary abstraction while preventing code duplication. Platform controllers CAN access ai_brain directly when needed.
Platform Skins (UI Layer)
Contains:
- β Views (XML) - Platform-specific forms, kanban, tree views
- β JavaScript Renderers - Platform-specific canvas rendering
- β CSS Styles - Platform-specific styling
- β Platform-Specific Controllers (optional, only if needed for UI logic)
- β Seed Data (XML) - Platform registration, demo data (reinstallable)
Does NOT contain:
- β Data models (belongs in ai_brain)
- β Universal controllers (belongs in ai_sam)
ai_sam_workflows/ β Platform Skin (example)
βββ models/ β β SHOULD BE EMPTY or minimal extensions
βββ controllers/ β β Platform-specific controllers (if needed)
β βββ workflow_import_controller.py (workflow-specific UI logic)
βββ views/ β β Platform-specific views
β βββ workflow_definition_views.xml
β βββ workflow_execution_views.xml
β βββ workflow_menus.xml
βββ static/src/
β βββ workflows/ β β Platform-specific renderer
β βββ workflow_renderer.js (N8N-style node rendering)
β βββ workflow_toolbar.js (workflow-specific tools)
β βββ workflow_styles.css
βββ data/ β β Seed data (reinstallable)
β βββ workflow_platform.xml (platform registration)
β βββ workflow_templates.xml (demo templates)
βββ security/ β β UI-specific security rules
βββ ir.model.access.csv (view access only)
Platform-Specific Controllers:
Question: Do platform skins have their own controllers?
Answer: YES, but ONLY for platform-specific UI logic.
- β Universal query engines β ai_sam (work across all platforms)
- β Platform-specific UI logic β Platform skin (only needed for that skin)
# ai_sam_workflows/controllers/workflow_import_controller.py
class WorkflowImportController(http.Controller):
"""
Workflow-specific controller for N8N JSON import
This is UI logic specific to the workflows skin
"""
@http.route('/workflows/import/n8n', type='http', auth='user')
def import_n8n_json(self, file):
# Parse N8N JSON (specific to workflows platform)
# Create canvas, nodes, connections in ai_brain
# Return workflow ID
pass
@http.route('/workflows/export/n8n', type='http', auth='user')
def export_n8n_json(self, workflow_id):
# Read from ai_brain.canvas
# Convert to N8N JSON format (specific to workflows platform)
# Return JSON file
pass
Universal operations (used by 2+ platforms) β ai_sam controller
Platform-specific operations (used by 1 platform) β Platform skin controller (direct to ai_brain)
Benefits:
- β No unnecessary abstraction layers
- β No code duplication (DRY principle)
- β Platform controllers can access ai_brain directly
- β Shared logic centralized where it adds value
π― Benefits of Platform Skin Architecture
1. Data Safety:
- β Uninstall any platform skin β Data remains safe in ai_brain
- β Reinstall platform skin β Data is still there
- β Compliance-friendly (audit trails protected)
2. Debug Isolation:
- β "Debug UI issues 1 platform at a time"
- β Workflows broken? Uninstall ai_sam_workflows, debug, reinstall
- β Other platforms unaffected
- β Data untouched
3. Flexible Frontend Development:
- β Build web forms that query ai_brain directly (no ai_sam needed)
- β Build mobile app that hits ai_sam controllers
- β Build external dashboard that visualizes ai_brain data
- β Replace entire platform skin without losing data
4. Clean Separation:
- β Frontend developers work on skins (no database risk)
- β Backend developers work on ai_brain (no UI complexity)
- β Framework developers work on ai_sam (universal infrastructure)
π Module Dependencies
ai_sam_workflows ββ ai_sam_memory ββ€ ai_sam_creatives ββΌβββ ai_sam βββ ai_brain βββ base (Odoo core) [future skins] ββ Dependency Direction: Skins depend on ai_sam ai_sam depends on ai_brain ai_brain depends on base Data Flow: Skins (UI) β ai_sam (controllers/query engines) β ai_brain (data)
Installation Order:
base(Odoo core)ai_brain(data layer)ai_sam(framework)- Platform skins (optional, any order)
Uninstallation:
- β Can uninstall any skin (data safe)
- β Can uninstall ai_sam (if no skins installed)
- β Cannot uninstall ai_brain (base dependency, data layer)
π Uninstall Strategy
Platform Skin Uninstall:
# ai_sam_workflows/models/workflow_uninstall_wizard.py
class WorkflowUninstallWizard(models.TransientModel):
_name = 'workflow.uninstall.wizard'
def check_data_exists(self):
# Check if workflows exist in ai_brain
Canvas = self.env['canvas']
workflow_count = Canvas.search_count([('canvas_type', '=', 'workflow')])
if workflow_count > 0:
# Warn user
return {
'type': 'ir.actions.act_window',
'name': 'Workflows Exist',
'res_model': 'workflow.uninstall.wizard',
'view_mode': 'form',
'target': 'new',
}
def export_and_uninstall(self):
# Export workflow data (CSV/JSON)
# User downloads backup
# Then allow uninstall
# Data remains in ai_brain (still accessible if reinstalled)
pass
- User clicks "Uninstall ai_sam_workflows"
- Wizard checks ai_brain for workflow data
- If data exists β Offer export option
- User downloads backup (optional)
- Uninstall proceeds
- Data remains in ai_brain (not deleted)
- If user reinstalls β Data is still there!
π Future: Query Engines and Web Forms
"Now I could start to build our next step around ai_brain and initiate a simple web form and various query engines"
Architecture Enables This:
Example: Simple Web Form (No Platform Skin Needed)
<!-- simple_web_module/views/simple_form.xml -->
<form string="Query Workflows">
<field name="date_from"/>
<field name="date_to"/>
<button name="query_workflows" string="Search" type="object"/>
</form>
# simple_web_module/models/simple_query.py
class SimpleQuery(models.TransientModel):
_name = 'simple.query'
date_from = fields.Date()
date_to = fields.Date()
def query_workflows(self):
# Query ai_brain directly!
Canvas = self.env['canvas']
workflows = Canvas.search([
('create_date', '>=', self.date_from),
('create_date', '<=', self.date_to),
])
# Return data (no complex UI needed)
return {
'type': 'ir.actions.act_window',
'name': 'Results',
'res_model': 'canvas',
'view_mode': 'tree,form',
'domain': [('id', 'in', workflows.ids)],
}
Because ALL data is in ai_brain, you can query it from ANYWHERE (platform skins, web forms, mobile apps, external APIs)
π Summary
Golden Rules:
-
Data Layer (ai_brain):
- ALL data models
- No views, no controllers
- Protected, persistent, queryable
-
Framework Layer (ai_sam):
- Canvas skeleton core
- Universal services
- Universal controllers (query engines)
- No data models
-
UI Layer (Platform Skins):
- Views (XML)
- Renderers (JS/CSS)
- Platform-specific controllers (UI logic only)
- No data models
-
Controllers (Hybrid Approach - Option C):
- Universal operations (2+ platforms) β ai_sam
- Platform-specific operations (1 platform) β Platform skin (direct to ai_brain)
- Optimize for simplicity, not abstraction
If losing it would make a customer angry β ai_brain
If it's UI-specific and safe to remove β Platform skin
If it's universal infrastructure β ai_sam
π Lessons Learned: Workflows Platform Correction (2025-10-12)
The Mistake:
During Phase 3 extraction (2025-10-11), we initially moved workflow data models to ai_sam_workflows.
- Moved 20 data models from ai_brain to ai_sam_workflows
- Treated ai_sam_workflows as standalone module instead of Platform Skin
- Followed incorrect pattern from initial extraction
- β Uninstalling ai_sam_workflows would delete user workflow data
- β Violated data safety principles
- β Broke compliance/audit trail requirements (HIPAA, GDPR, SOX)
- β Contradicted original ai_brain design intent (pure data layer)
- β Broke "debug UI issues 1 platform at a time" strategy
- β Created data loss risk on module uninstall
The Fix:
Moved all 20 workflow data models back to ai_brain (2025-10-12).
- Archived current state (safety first)
- Moved all 20 model files back to ai_brain/models/
- Updated ai_brain/models/__init__.py with imports
- Cleared ai_sam_workflows/models/__init__.py (UI-only)
- Updated security rules (already in ai_brain)
- Updated both module manifests with Platform Skin documentation
- Created comprehensive correction summary
- β Data survives module uninstalls
- β Audit trails protected
- β Platform Skin Model correctly implemented
- β "Debug UI issues 1 platform at a time" strategy enabled
- β Compliance requirements met
- β Uninstall wizard strategy now viable
Key Insights:
The Golden Rule:
"If losing it would make a customer angry, it belongs in ai_brain" - This rule is non-negotiable.
- Would losing this on uninstall anger customers? β ai_brain
- Is this just a UI preference? β Platform skin
- Is this execution history or audit data? β ai_brain (always!)
Real-World Scenario:
User: "I want to uninstall the workflows UI to debug issues" Developer: "Sure, uninstalling ai_sam_workflows..." User: "Wait, what happened to all my workflows?!" Developer: "Oh no... they're gone..." β
User: "I want to uninstall the workflows UI to debug issues" Developer: "Sure, uninstalling ai_sam_workflows..." User: "Great! When I reinstall, will my workflows still be there?" Developer: "Absolutely! All data is safe in ai_brain" β
Compliance Perspective:
- HIPAA: Audit trails must be immutable and persistent
- GDPR: Data retention policies must be enforced
- SOX: Financial transaction history cannot be deleted
- Platform skins: UI preferences, not data stores
Apply to Other Modules:
| Module | Status | Action |
|---|---|---|
| ai_sam_memory | β Already correct | Ensure only UI components in module |
| ai_sam_creatives | β Already correct | Ensure only UI components in module |
| Future Platform Skins | Follow this pattern | NEVER put data models in platform modules |
Rules for Future Platform Skins:
- β NEVER put data models in platform modules
- β ALWAYS put data models in ai_brain
- β Platform skins = Views + JS/CSS + Platform-specific controllers only