Solanasis Custom ERP/CRM Platform — Build Plan

Date: 2026-03-11 Status: Active Planning Document Related:

  • open-source-erp-research.md — Original ERP platform research
  • erp-crm-plugins-research.md — Plugin/licensing analysis, two-track strategy
  • technical-reference-frappe-framework.md — Frappe hook system, lifecycle events, override mechanisms
  • technical-reference-frappe-crm.md — Frappe CRM feature inventory, replication guide
  • matchkeyz-to-frappe-translation-guide.md — Pattern-by-pattern implementation specs with code

CRITICAL STRATEGIC DECISION

We are building our own platform. While we start from ERPNext/Frappe as the foundation, we are intentionally diverging. This means:

  • We do NOT need to maintain easy upstream upgradability. The cost of staying compatible with upstream ERPNext releases is not worth the constraint it places on our product. We will cherry-pick security patches and critical fixes, but we are not tracking upstream versions.
  • We are building custom Frappe apps that replace major ERPNext modules (starting with CRM, eventually expanding to other modules as needed).
  • The Matchkeyz meta-driven architecture patterns are our secret weapon — we will incorporate patterns that ERPNext/Frappe CRM simply don’t have.
  • All custom code is proprietary — built on the GPL-3.0 Frappe Framework (safe for SaaS), never incorporating AGPL code into the resale product.

This is not a fork-and-tweak. This is a new product built on a proven foundation.


Current State (as of 2026-03-11)

ComponentStatus
ERPNext v16.9.0Running at db.zasage.us (localhost:8080)
Frappe CRM 1.60.1Installed (internal use / reference only)
Frappe Insights 2.2.13Installed (internal use / reference only)
Frappe WhatsApp 1.0.12Installed (MIT — safe for resale)
Custom Docker imagesolanasis/erpnext:v16-custom built and running
Cloudflare tunnelActive via claude-bot tunnel → db.zasage.us
GitHub forksdzinreach/erpnext, dzinreach/frappe

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│                    SOLANASIS PLATFORM                        │
│                                                             │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  CUSTOM FRAPPE APPS (Proprietary — GPL SaaS-safe)     │  │
│  │                                                       │  │
│  │  solanasis_core     — Meta-schema engine, RecSaver,   │  │
│  │                       field-level audit, universal     │  │
│  │                       soft-delete, polymorphic entities│  │
│  │                                                       │  │
│  │  solanasis_crm      — Pipeline, deals, leads, scoring,│  │
│  │                       unified timeline, multi-table    │  │
│  │                       forms, email sequences           │  │
│  │                                                       │  │
│  │  solanasis_whitelabel — Deep UI reskin, per-tenant     │  │
│  │                        theming, dark mode, custom nav  │  │
│  │                                                       │  │
│  │  solanasis_comms    — WhatsApp, Twilio, cold email     │  │
│  │                       tool integration, email tracking │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  FRAPPE FRAMEWORK (GPL-3.0) + ERPNEXT (GPL-3.0)      │  │
│  │  DocType system, REST API, auth, WebSocket,           │  │
│  │  Accounting, Inventory, HR, Manufacturing             │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌───────────────────────────────────────────────────────┐  │
│  │  INFRASTRUCTURE                                       │  │
│  │  MariaDB 10.6 | Redis | Docker | Cloudflare Tunnel   │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

Why We’re Diverging From Upstream

ConcernOur Position
”What about upstream security patches?”We monitor upstream releases and cherry-pick security fixes into our fork. This is a manual process but only needed for critical CVEs — not every release.
”What about new ERPNext features?”We evaluate each release. If a feature is useful, we port it. But we’re building features they don’t have, so upstream becomes less relevant over time.
”What if we fall too far behind?”That’s the point. Our product will be so different that “behind” doesn’t apply. We share the same foundation (Frappe Framework) but the application layer is ours.
”Isn’t this more work?”Yes. But the alternative is being constrained to ERPNext’s UX decisions, AGPL licensing traps, and a CRM that Frappe themselves have abandoned for new development. The custom build IS the product.

What Matchkeyz Teaches Us (Patterns to Incorporate)

After deep analysis of the Matchkeyz codebase (/mnt/c/_matchkeyz_code/qa/), these are the architectural patterns that ERPNext/Frappe lack and that we will build into solanasis_core:

Pattern 1: Meta-Driven Table Registry

Matchkeyz has it: Every entity is registered in a tables table with parent relationships, JOIN semantics (join_on_col, parent_table_join_col, join_sql), form references, and table type classification. The framework auto-generates SQL JOINs for any view without developer intervention.

Frappe lacks it: DocTypes define fields and relationships, but JOIN logic is hardcoded per report/query. There’s no universal “give me a form spanning tables X, Y, Z with auto-generated joins.”

What we’ll build: A Solanasis Table Registry DocType that enriches Frappe’s DocType system with explicit join semantics, parent-child hierarchy metadata, and auto-SQL generation capabilities. This sits alongside Frappe’s DocType system, not replacing it — extending it.

Pattern 2: Multi-Table Form Composition

Matchkeyz has it: A single form (views table) can span multiple database tables via view_tables. Fields from different tables appear in the same form. Sections can embed sub-forms via for_view_id. Per-form field overrides (editable, required, name, placeholder) let the same field appear differently in different contexts.

Frappe lacks it: Forms map 1:1 to DocTypes. If you want data from multiple DocTypes in one view, you build a custom page or use Dashboard links. No per-form field overrides.

What we’ll build: A Solanasis View system that composes forms from multiple DocTypes with per-view field overrides. This is the foundation for building CRM deal views that show contact info, activity history, email threads, and deal data in a single unified form — without building separate custom pages for each combination.

Pattern 3: Field-Level Modification History

Matchkeyz has it: mods + mod_vals tables track every individual field change with old/new values, linked to the user, form, auto-action, and activity. Virtual “Record-Created” and “Record-Updated” sub-tables appear as first-class child tables.

Frappe has partially: Document versioning exists but tracks whole-document JSON diffs, not individual field changes. No easy way to query “who changed field X on record Y and when?”

What we’ll build: A Solanasis Audit Trail system that tracks field-level changes in a queryable format. For the CRM, this means: “Show me every time this deal’s value changed, who changed it, and from what to what.” This is essential for compliance, accountability, and the activity timeline.

Pattern 4: Polymorphic Entities with Virtual Table IDs

Matchkeyz has it: Single-table inheritance where contacts serves as People, Organizations, and Groups via contact_type_id. Negative table IDs (-101, -110) create virtual views with their own forms and child tables.

Frappe lacks it: Separate DocTypes for Lead, Customer, Supplier, etc. No single-table-inheritance pattern. Converting a Lead to a Customer creates a new record and links them, rather than changing a type flag.

What we’ll build: A unified Solanasis Contact DocType that can be a Person, Organization, or Group — with type-specific views and child tables. Conversion between types (Lead → Customer) is a field change, not a record migration. This dramatically simplifies the CRM data model and eliminates the fragmentation between Lead, Customer, Supplier, and Contact DocTypes that plagues ERPNext.

Pattern 5: Data-Driven Field Definitions with Runtime Schema Changes

Matchkeyz has it: Fields are data records. Adding a field is a database operation that both creates metadata AND alters the physical table via stored procedures. No code deployment needed.

Frappe has partially: Custom Fields exist and can be added at runtime via UI. But they’re second-class citizens — they don’t participate in the same way as core fields, and the customization options are limited.

What we’ll build: Enhanced custom field capabilities that match Matchkeyz’s sophistication — calculated fields (SQL expressions), per-form visibility/editability overrides, field-level encryption, edit-once restrictions, and admin-only fields. All configurable via the Solanasis admin UI.

Pattern 6: Universal Soft Delete with Lifecycle States

Matchkeyz has it: rec_type_id with states: active, archived, disabled, deleted, hidden, system-disabled, invited, suggested, denied. Every query filters by is_exclude flag.

Frappe has partially: docstatus (Draft=0, Submitted=1, Cancelled=2) for amendable documents. No universal soft-delete — deletion is usually hard delete with an optional “Trash” for some types.

What we’ll build: A universal rec_status field on all Solanasis DocTypes with configurable lifecycle states. Records are never hard-deleted. This is critical for audit compliance and data recovery.

Pattern 7: Auto-Actions and Scheduled Tasks as Data

Matchkeyz has it: Auto-actions (triggers), templates, and scheduled tasks share the views table. They have trigger criteria (filters), field mappings, versioning, and execution history — all configurable without code.

Frappe has partially: Server Scripts and Scheduled Jobs exist but require Python code. Notification rules are configurable but limited in what they can do.

What we’ll build: A Solanasis Automation engine where trigger rules, field mappings, and scheduled tasks are fully data-driven. A non-developer admin can set up “When a Deal moves to Won stage, create a Customer record and send a WhatsApp message” without writing code.

Pattern 8: Section-Based Form Layout with Grid Positioning

Matchkeyz has it: Sections with row, col for grid positioning, parent_section_id for nesting, for_view_id for embedding sub-forms.

Frappe has limited: Section Break, Column Break, Tab Break — linear layout only. No grid positioning, no section nesting, no sub-form embedding.

What we’ll build: Enhanced form layouts using Frappe UI’s Vue components with CSS Grid support, nested sections, and embeddable sub-views. This makes forms feel modern and information-dense without being overwhelming.


Custom App Specifications

App 1: solanasis_core

Purpose: Foundation layer providing the meta-schema engine and infrastructure patterns from Matchkeyz. All other Solanasis apps depend on this.

DocTypes to create:

DocTypePurposeKey Fields
Solanasis Table RegistryMeta-registry extending DocTypedoctype_link, parent_registry, join_column, join_sql, table_type
Solanasis Field OverridePer-form field customizationsource_field, target_view, is_editable, is_required, label_override, placeholder
Solanasis Audit EntryModification history headerdoctype, docname, action_type, user, form_used, memo
Solanasis Audit ValueField-level change detailaudit_entry, field, old_value, new_value, old_id, new_id
Solanasis Lifecycle StateConfigurable record statesstate_name, is_active, is_excluded, color, icon
Solanasis Automation RuleData-driven trigger rulestrigger_doctype, trigger_event, condition_filters, actions
Solanasis Automation ActionAction definitionsaction_type, target_doctype, field_mapping, template

Server-side infrastructure:

  • SolanasisModel base class (Python) extending Frappe’s Document with:
    • Automatic audit trail generation on save
    • Universal soft-delete (override delete())
    • Lifecycle state management
    • Field-level change detection
  • RecSaver API endpoint for multi-DocType saves from composite forms
  • Auto-JOIN SQL generator from Table Registry metadata

App 2: solanasis_crm

Purpose: Modern CRM replacing both ERPNext’s built-in CRM and serving as the alternative to AGPL Frappe CRM. Built entirely on solanasis_core + Frappe Framework.

DocTypes to create:

DocTypePurposeKey Fields
Solanasis ContactUnified Person/Org/Group (polymorphic)contact_type, name, email, phone, company, title, lifecycle_state, lead_score
Solanasis DealSales pipeline dealcontact, deal_stage, value, probability, expected_close, assigned_to, source
Solanasis Deal StageConfigurable pipeline stagesstage_name, order, default_probability, color, is_won, is_lost
Solanasis ActivityUnified timeline entrycontact, deal, activity_type, subject, detail, timestamp, user
Solanasis Activity TypeActivity categoriestype_name, icon, color (email, call, note, meeting, task, whatsapp)
Solanasis Email SequenceMulti-step drip campaignsname, steps, trigger_criteria, status
Solanasis Email StepIndividual sequence stepsequence, delay_days, subject, body_template, condition
Solanasis Lead Score RuleScoring engine rulesfield, operator, value, points, category
Solanasis CRM SettingsPipeline config, defaultsdefault_stages, scoring_weights, auto_assignment_rules

Custom Vue.js pages:

RoutePurposeKey UI Elements
/app/solanasis-dealsPipeline Kanban boardDrag-and-drop columns by stage, deal cards with value/contact/days-in-stage, quick filters
/app/solanasis-deals/{id}Deal detailUnified activity timeline (left), deal fields (right), contact info card, quick actions bar
/app/solanasis-contactsContact list with smart filtersCombined People/Orgs view, inline search, lead score badges, last activity date
/app/solanasis-contacts/{id}Contact detailMulti-tab: Overview, Deals, Activities, Emails, Documents, Relationships
/app/solanasis-dashboardSales analyticsPipeline value by stage, conversion funnel, activity metrics, revenue forecast (eCharts)
/app/solanasis-sequencesEmail sequence builderVisual step editor, delay configuration, template preview, performance metrics

Integrations:

  • Email: Built on Frappe’s email infrastructure (GPL) with added open/click tracking (tracking pixel + link wrapping)
  • WhatsApp: Via frappe_whatsapp (MIT) — safe for resale
  • Telephony: Direct Twilio Python SDK (MIT) — click-to-call, call logging
  • Cold email: API webhook integration with external tools (Instantly.ai, Smartlead)

App 3: solanasis_whitelabel

Purpose: Complete UI transformation. Solanasis brand palette, per-tenant theming, dark mode.

Implementation:

  • CSS variable overrides: Navy #020532, Parchment FEF9F1, Copper C47A3D
  • Custom login page (Jinja2 template override)
  • Redesigned sidebar navigation
  • Command palette enhancement (Cmd+K)
  • Per-tenant Solanasis Theme DocType (colors, logo, fonts per client)
  • Dark mode toggle
  • Hide all ERPNext/Frappe branding

App 4: solanasis_comms

Purpose: Communication layer — WhatsApp, telephony, email campaigns, cold outreach integration.

Key components:

  • WhatsApp messaging via frappe_whatsapp (MIT) or direct Meta Cloud API
  • Twilio click-to-call and call logging via Python SDK (MIT)
  • Email sequence execution engine (sends from Frappe’s email, tracks opens/clicks)
  • Cold email tool webhook receiver (syncs leads/responses from external tools)
  • Unified communication log feeding into Solanasis Activity

Build Phases

Phase 1: solanasis_core Foundation

What: Build the core infrastructure layer — audit trail, soft delete, lifecycle states, base model class.

Deliverables:

  • Frappe custom app scaffold: bench new-app solanasis_core
  • SolanasisModel base class (extends frappe.model.document.Document)
    • Auto audit trail via on_update / after_insert hooks
    • Field-level change detection via get_doc_before_save() + field comparison
    • Soft-delete interception via on_trash override
    • get_field_history(fieldname) helper for per-field history queries
    • See matchkeyz-to-frappe-translation-guide.md Pattern 2 for full code
  • Solanasis Audit Entry DocType (maps to Matchkeyz mods table)
    • Fields: ref_doctype, ref_docname, action_type, user, timestamp, form_used, memo, automation_rule
    • Child table: values → Solanasis Audit Value
  • Solanasis Audit Value DocType (maps to Matchkeyz mod_vals table)
    • Fields: field_name, field_label, old_value, new_value, old_ref_name, new_ref_name
  • Solanasis Lifecycle State DocType + fixture data
    • Default states: Active, Archived, Deleted, Disabled, Draft
    • Fields: state_name, is_active, is_excluded, color, icon
  • Universal audit via doc_events["*"] wildcard hook
    • on_update + after_insert → create Solanasis Audit Entry
    • on_trash → intercept and soft-delete (set lifecycle_state=Deleted)
  • hooks.py with: doc_events, after_install, after_migrate, fixtures
  • Unit tests for audit trail generation (insert + update + field comparison)
  • Unit tests for soft-delete behavior (verify record not hard-deleted)

Key technical decisions:

  • Use "*" doc_events hook for universal coverage (all DocTypes get audit)
  • Store audit values as strings (Long Text) for uniformity — Matchkeyz does the same
  • Audit entries use child table (not separate join) for atomic creation
  • Lifecycle state is a Link field, not Select — allows runtime state addition

Dependencies: None (pure Frappe Framework)

Phase 2: solanasis_crm — Data Model

What: Create all CRM DocTypes, relationships, and server-side logic.

Deliverables:

  • Solanasis Contact DocType (polymorphic — maps to Matchkeyz Pattern 7)
    • contact_type Select: Person/Organization/Group
    • Type-specific sections with depends_on visibility
    • Common fields: email, phone, lifecycle_state, lead_score, assigned_to, source
    • Extends SolanasisModel for automatic audit trail
    • override_doctype_class for Frappe’s Contact → sync to Solanasis Contact
  • Solanasis Deal + Solanasis Deal Stage DocTypes
    • Deal: contact (Link), deal_stage (Link), value (Currency), probability, expected_close
    • Stage: stage_name, order, default_probability, color, is_won, is_lost
    • on_update hook: auto-create ERPNext Customer when deal stage is_won=True
  • Solanasis Activity DocType (write-time aggregation — improvement over Frappe CRM)
    • Fields: contact, deal, activity_type (Link), subject, detail, timestamp, user
    • Created by hooks on: email sent, call logged, note added, field changed, WhatsApp sent
    • This replaces Frappe CRM’s runtime aggregation from 6 tables
  • Solanasis Activity Type DocType (fixture)
    • Types: Email, Call, Note, Meeting, Task, WhatsApp, Field Change, Conversion
  • Solanasis Lead Score Rule DocType + scoring engine
  • Solanasis Email Sequence + Solanasis Email Step DocTypes
  • Solanasis Lost Reason DocType (maps to Frappe CRM’s CRM Lost Reason)
  • Solanasis CRM Settings DocType
  • API endpoints (solanasis_crm/api/):
    • deals.py: move_deal, get_pipeline_data, mark_won, mark_lost
    • contacts.py: convert_type, merge_contacts, get_contact_timeline
    • data.py: get_data (generic list/kanban/group_by — maps to Frappe CRM’s api/doc.py)
    • dashboard.py: pipeline_value, conversion_funnel, activity_metrics
  • Default fixtures: pipeline stages, activity types, lead score rules
  • Migration script: import ERPNext Leads → Solanasis Contacts, Opportunities → Deals

Dependencies: solanasis_core

Phase 3: solanasis_crm — Vue.js UI

What: Build the modern frontend pages using Frappe UI (Vue 3 + Tailwind, both MIT).

Tech stack: Vue 3 + Vite + frappe-ui + Vue Router + Pinia + Tailwind CSS (all MIT)

Component architecture (informed by Frappe CRM’s 100+ component inventory):

solanasis_crm/frontend/src/
├── App.vue
├── router.js
├── stores/                           # Pinia state management
│   ├── deals.js
│   ├── contacts.js
│   └── user.js
├── layouts/
│   ├── AppLayout.vue                 # Desktop: sidebar + content
│   ├── MobileLayout.vue              # Mobile: hamburger + content
│   └── SidePanelLayout.vue           # Detail: timeline + metadata
├── pages/
│   ├── Deals.vue                     # Pipeline Kanban + list toggle
│   ├── DealDetail.vue                # Side panel: timeline left, fields right
│   ├── Contacts.vue                  # Contacts list with smart filters
│   ├── ContactDetail.vue             # Multi-tab: Overview, Deals, Activities
│   ├── Dashboard.vue                 # eCharts: pipeline, funnel, metrics
│   └── EmailSequences.vue            # Sequence builder
├── components/
│   ├── KanbanBoard.vue               # Drag-and-drop pipeline columns
│   ├── KanbanCard.vue                # Deal card (value, contact, days)
│   ├── ActivityTimeline.vue          # Unified activity feed
│   ├── ActivityItem.vue              # Single activity (email/call/note/etc)
│   ├── ViewControls.vue              # List/Kanban/GroupBy toggle + filters
│   ├── QuickFilterField.vue          # Inline filter inputs
│   ├── ColumnSettings.vue            # Column visibility/order config
│   ├── CompositeForm.vue             # Multi-DocType form (Pattern 5)
│   └── modals/
│       ├── DealModal.vue             # Quick deal creation
│       ├── ContactModal.vue          # Quick contact creation
│       ├── LostReasonModal.vue       # Why deal was lost
│       └── ConvertModal.vue          # Contact type conversion
└── composables/
    ├── useDeals.js                   # Deal data fetching + mutations
    ├── useContacts.js                # Contact data + search
    └── useActivities.js              # Activity timeline data

Deliverables:

  • Vue 3 + Vite + frappe-ui project scaffold
  • Route registration via website_route_rules in hooks.py
  • Pipeline Kanban page with drag-and-drop (uses get_pipeline_data API)
  • Deal detail page with unified activity timeline (left) + deal fields (right)
  • Contact list page with smart filters, inline search, lead score badges
  • Contact detail page with multi-tab layout (Overview, Deals, Activities, Docs)
  • Sales dashboard with eCharts (pipeline value, conversion funnel, activity metrics)
  • ViewControls component (list/kanban/group_by toggle with saved preferences)
  • Modal-based CRUD (create records without losing context)
  • Mobile-responsive layouts for all pages
  • Real-time updates via frappe.realtime.on() (deal moved → Kanban updates)

Dependencies: Phase 2 (DocTypes must exist for the UI to query)

Phase 4: solanasis_whitelabel

What: Complete UI reskin.

Deliverables:

  • Solanasis brand CSS variables and theme
  • Custom login page
  • Redesigned sidebar navigation
  • Solanasis Theme DocType for per-tenant branding
  • Dark mode implementation
  • All ERPNext/Frappe branding removed
  • Command palette (Cmd+K) enhancement

Dependencies: Can start in parallel with Phase 2/3

Phase 5: solanasis_comms

What: Communication integrations.

Deliverables:

  • WhatsApp send/receive via frappe_whatsapp
  • Twilio click-to-call integration
  • Email open/click tracking (tracking pixel + link wrapping)
  • Email sequence execution engine
  • Cold email tool webhook integration
  • All communications logged as Solanasis Activity entries

Dependencies: Phase 2 (needs Activity DocType)

Phase 6: solanasis_core — Advanced (Table Registry, Multi-Table Forms, Automations)

What: The advanced meta-schema patterns from Matchkeyz.

Deliverables:

  • Solanasis Table Registry DocType with JOIN semantics
  • Solanasis Field Override DocType for per-form customization
  • Auto-JOIN SQL generator
  • RecSaver multi-DocType save endpoint
  • Solanasis Automation Rule + Solanasis Automation Action DocTypes
  • Automation execution engine (data-driven triggers, no code needed)
  • Composite form rendering (multi-DocType forms from View definition)

Dependencies: Phase 1 (core foundation), real usage data from Phases 2-5 to inform design


Matchkeyz Patterns → Solanasis Mapping

Matchkeyz PatternMatchkeyz ImplementationSolanasis Implementation
Tables-as-data registrytables table with 67 fieldsSolanasis Table Registry DocType extending Frappe’s DocType
Fields-as-datafields table + p_field_edit procEnhanced Custom Fields with calc expressions, per-form overrides
Views-as-data (forms)views + view_tables + view_fieldsSolanasis View DocType with multi-DocType composition
Modification historymods + mod_vals tablesSolanasis Audit Entry + Solanasis Audit Value DocTypes
Polymorphic contactscontacts with negative table_idsSolanasis Contact with contact_type field + type-specific child tables
RecSaver (generic save)Single API for multi-table savesCustom Frappe API endpoint handling composite form saves
Soft deleterec_type_id with is_excludelifecycle_state field with Solanasis Lifecycle State configuration
Auto-actionsActions in views tableSolanasis Automation Rule + Solanasis Automation Action DocTypes
Section grid layoutsections with row/col/nestingVue components with CSS Grid + nested section support
Filter/Sort systemfilters + filter_items + sortBuild on Frappe’s existing filter system + custom enhancements

What We’re NOT Building (Yet)

These are ERPNext modules we’ll use as-is for now:

  • Accounting — ERPNext’s accounting module is solid. No need to rebuild.
  • Inventory/Stock — Same. Works well.
  • HR/Payroll — Same. Use as-is.
  • Manufacturing — Same. Use as-is.
  • Projects — Evaluate later. May need CRM integration enhancements.

The custom build focuses on CRM, UI, communications, and the meta-schema engine — where ERPNext is weakest and where our Matchkeyz patterns give us a genuine advantage.


Docker Image Strategy (Going Forward)

Base: frappe/frappe:version-16         # Frappe Framework (GPL)
  └── + ERPNext version-16             # ERP backbone (GPL)
  └── + frappe_whatsapp version-16     # WhatsApp (MIT)
  └── + solanasis_core                 # Our foundation (Proprietary)
  └── + solanasis_crm                  # Our CRM (Proprietary)
  └── + solanasis_whitelabel           # Our UI (Proprietary)
  └── + solanasis_comms                # Our comms layer (Proprietary)

Tag: solanasis/platform:v1.x.x

Internal dev instance (current db.zasage.us) also includes:

  • Frappe CRM (AGPL — reference only, never ships to clients)
  • Frappe Insights (AGPL — reference only, never ships to clients)

License Compliance Checklist

  • All custom apps (solanasis_*) built on GPL Frappe Framework — SaaS deployment = no distribution = no source disclosure
  • No AGPL code in client-facing image (Frappe CRM, Helpdesk, Insights, Raven, Telephony excluded)
  • frappe_whatsapp (MIT) — safe to include
  • GPL license notice maintained in codebase
  • Product never called “ERPNext” or “Frappe” in marketing/branding
  • JavaScript distribution risk: custom Vue components served to browsers are built on MIT-licensed Frappe UI — keep proprietary business logic in server-side Python, not client-side JS where possible
  • CORE_PATCHES.md tracks any direct modifications to upstream Frappe/ERPNext
  • Legal review before first client deployment

File Locations

/home/zasage/_solanasis/
├── frappe_docker/                    # Docker deployment
│   ├── compose.solanasis.yaml        # Production compose
│   ├── .env                          # Secrets (gitignored)
│   ├── apps.json                     # App manifest for image builds
│   └── images/                       # Dockerfiles
├── erpnext/                          # Fork: dzinreach/erpnext
├── frappe/                           # Fork: dzinreach/frappe
├── solanasis_core/                   # (TO CREATE) Custom core app
├── solanasis_crm/                    # (TO CREATE) Custom CRM app
├── solanasis_whitelabel/             # (TO CREATE) Custom UI app
├── solanasis_comms/                  # (TO CREATE) Custom comms app
├── solanasis-docs/                   # Documentation
│   ├── solanasis-custom-erp-crm-build-plan.md        # THIS FILE — master plan
│   ├── erp-crm-plugins-research.md                    # Licensing & plugin analysis
│   ├── technical-reference-frappe-framework.md         # Frappe hooks, lifecycle, overrides
│   ├── technical-reference-frappe-crm.md               # CRM feature replication guide
│   ├── matchkeyz-to-frappe-translation-guide.md        # Pattern implementation specs
│   └── open-source-erp-research.md                     # Original platform research
├── CORE_PATCHES.md                   # Upstream modification tracker
└── backups/                          # Local backups

Implementation Quick Reference

How Solanasis Apps Hook Into Frappe

All custom behavior flows through hooks.py in each app. Here’s the hook architecture:

solanasis_core/hooks.py
├── doc_events["*"]["on_update"]      → Universal audit trail
├── doc_events["*"]["after_insert"]   → Audit trail for new records
├── doc_events["*"]["on_trash"]       → Soft-delete interception
├── override_doctype_class            → Override Contact, Customer behavior
├── after_install                     → Seed lifecycle states, table registry
├── after_migrate                     → Schema updates
└── fixtures                          → Lifecycle states, activity types

solanasis_crm/hooks.py
├── doc_events["Solanasis Deal"]["on_update"]  → Customer creation on Won
├── website_route_rules                         → /crm/* → Vue SPA
├── scheduler_events.hourly                     → Email sequences, lead scoring
├── scheduler_events.daily                      → Stale deal alerts
├── app_include_css                             → CRM styles
└── fixtures                                    → Deal stages, lead sources

solanasis_whitelabel/hooks.py
├── app_include_css                   → Theme CSS variables
├── app_include_js                    → Theme toggle, nav override
├── base_template                     → Custom login page
├── jinja.methods                     → Template helpers
└── extend_bootinfo                   → Per-tenant theme config

solanasis_comms/hooks.py
├── doc_events["WhatsApp Message"]    → Activity creation on send/receive
├── scheduler_events.cron["*/5"]      → Check incoming WhatsApp
├── scheduler_events.hourly           → Process email sequences
└── doc_events["Communication"]       → Email tracking pixel injection

Document Lifecycle Hook Order (for reference)

On INSERT: before_insertbefore_validatevalidatebefore_save → [DB INSERT] → after_inserton_updateon_change

On UPDATE: before_validatevalidatebefore_save → [DB UPDATE] → on_updateon_change

On DELETE: on_trash → [DB DELETE] → after_delete

See technical-reference-frappe-framework.md for complete flow diagrams with every sub-step.