2024-11-23
Version Everything: How PMFA Eliminates Migrations and Downtime
Scenario: Your ERP system has been running for 3 years. You have 50,000 invoices in the database. Client requests adding a new approval step to the workflow.
SAP/Oracle approach:
- Development (3-6 weeks)
- Database migration (all existing documents)
- Testing (2-4 weeks)
- Production transport (scheduled downtime)
- Rollback plan (if something breaks)
- Total cost: $200K+, 3 months, high risk
PMFA approach:
- Modify YAML workflow definition (5 minutes)
- Deploy new version (instant)
- Old invoices stay on old workflow
- New invoices use new workflow
- Total cost: $0, 5 minutes, zero risk
The difference? Versioning.
The Problem: Migrations Kill ERP Projects
SAP Horror Story (Real Example)
Company: European retailer, 2,000 employees
Project: S/4HANA upgrade + new purchase order workflow
Data migration: 8 million documents from legacy system
Timeline:
- Months 1-3: Analysis & design
- Months 4-8: Development
- Months 9-11: Data migration testing
- Month 12: Go-live attempt #1 → FAILED (data corruption)
- Months 13-14: Rollback + bug fixes
- Month 15: Go-live attempt #2 → SUCCESS (but with compromises)
Final cost: €12M
Downtime: 72 hours (planned), additional 48 hours (unplanned)
Lost revenue: €3M+ (can't process orders during downtime)
Root cause:
-- Old workflow (3 approval steps)
UPDATE invoices SET status = 'approved'
WHERE approval_level = 3;
-- New workflow (4 approval steps)
-- What happens to 50,000 existing invoices
-- that only have 3 approval records?
-- Answer: CHAOS
Why migrations are dangerous:
- Data schema changes - Adding columns = table rewrites = locks
- Business logic changes - Old data doesn't match new rules
- Zero rollback - Once migrated, can't easily go back
- Downtime required - Can't run old + new system simultaneously
- Testing nightmare - Impossible to test all edge cases
PMFA Solution: Version EVERYTHING
Core Principle
Traditional ERP: One schema, one workflow version. Changes = migrations.
PMFA: Multiple versions coexist. Old documents use old logic, new documents use new logic.
PMFA meta-model:
# meta_model version 1 (deployed 2021)
Invoice:
fields:
- number: string
- amount: decimal
- status: enum[draft, approved, paid]
workflow:
states: [draft, approval_1, approval_2, approved]
# meta_model version 2 (deployed 2023)
Invoice:
fields:
- number: string
- amount: decimal
- status: enum[draft, approved, paid]
- tax_category: string # NEW FIELD
workflow:
states: [draft, approval_1, approval_2, approval_3, approved] # NEW STATE
How PMFA handles this:
Every document stores:
CREATE TABLE invoices (
id UUID PRIMARY KEY,
meta_model_id INTEGER, -- Points to version 1 or 2
workflow_version INTEGER, -- Points to workflow version
data JSONB -- Actual document data
);
When you deploy a new version:
- PMFA creates
meta_model_v2schema in metadata store - New invoices use
meta_model_id = 2 - Old invoices keep
meta_model_id = 1 - Both workflows execute simultaneously
- Zero migration. Zero downtime. Zero risk.
Real-World Example: Bank Approval Workflow
Company: Serbian bank, 150 branches
Requirement: Loan approval process changes 3 times per year (compliance)
2021 workflow: 2 approval steps (branch manager → regional director)
2023 workflow: 3 approval steps (+ compliance officer)
2024 workflow: 4 approval steps (+ anti-fraud check)
Traditional approach:
// Hardcoded business logic
if (loan.getStatus() == LoanStatus.PENDING) {
if (loan.getApprovalCount() == 2) {
loan.setStatus(LoanStatus.APPROVED);
}
}
// Changing this = recompile + test + deploy + MIGRATION
Every change:
- 3 weeks development
- 2 weeks testing
- 1 week migration
- $50K+ per change
- $150K/year just for workflow updates
PMFA approach:
# 2021 workflow (version 1)
LoanApproval:
workflow_version: 1
states:
- draft
- branch_manager_approval
- regional_director_approval
- approved
# 2023 workflow (version 2)
LoanApproval:
workflow_version: 2
states:
- draft
- branch_manager_approval
- compliance_officer_approval
- regional_director_approval
- approved
# 2024 workflow (version 3)
LoanApproval:
workflow_version: 3
states:
- draft
- branch_manager_approval
- compliance_officer_approval
- anti_fraud_check
- regional_director_approval
- approved
When bank changes workflow:
- Update YAML file (5 minutes)
- Deploy new version (instant)
- Old loans continue on old workflow
- New loans use new workflow
- Zero migration. Zero downtime. Zero cost.
Result:
- 3 workflow changes/year
- 15 minutes total deployment time
- $0 migration cost
- Saved $150K/year
Technical Deep Dive: How It Works
1. Document Version Binding
Every document is bound to specific meta-model + workflow version:
interface Document {
id: string;
meta_model_id: number; // Which entity definition
workflow_version: number; // Which workflow logic
data: object; // Actual fields
created_at: timestamp;
updated_at: timestamp;
}
Example:
{
"id": "inv-2021-00123",
"meta_model_id": 1,
"workflow_version": 1,
"data": {
"number": "INV-2021-00123",
"amount": 5000,
"status": "approved"
}
}
{
"id": "inv-2024-99999",
"meta_model_id": 2,
"workflow_version": 3,
"data": {
"number": "INV-2024-99999",
"amount": 8000,
"status": "approved",
"tax_category": "VAT-20"
}
}
Both invoices coexist. No migration needed.
2. Workflow Execution Engine
PMFA workflow engine loads correct version dynamically:
async function executeWorkflow(documentId: string) {
const doc = await getDocument(documentId);
// Load workflow definition for this specific version
const workflow = await getWorkflowVersion(
doc.meta_model_id,
doc.workflow_version
);
// Execute transitions based on loaded definition
const nextState = workflow.getNextState(doc.data.status);
// Apply business rules from that version
const validations = workflow.getValidations(nextState);
await applyValidations(doc, validations);
}
Key insight: Workflow logic is data, not code. Different documents can execute different logic.
3. Schema Compatibility
PMFA uses JSONB for flexible schema:
-- Version 1 documents
SELECT data->>'number', data->>'amount'
FROM invoices
WHERE meta_model_id = 1;
-- Version 2 documents
SELECT data->>'number', data->>'amount', data->>'tax_category'
FROM invoices
WHERE meta_model_id = 2;
No ALTER TABLE. No locks. No downtime.
4. Reporting Across Versions
Problem: How to query data when schema changes?
Solution: Abstract reporting layer:
// PMFA Report Definition (YAML)
InvoiceReport:
fields:
- number: invoice.data->>'number'
- amount: invoice.data->>'amount'
- tax: |
CASE
WHEN meta_model_id = 1 THEN NULL
WHEN meta_model_id >= 2 THEN invoice.data->>'tax_category'
END
Generated SQL:
SELECT
data->>'number' as number,
(data->>'amount')::decimal as amount,
CASE
WHEN meta_model_id = 1 THEN NULL
WHEN meta_model_id >= 2 THEN data->>'tax_category'
END as tax_category
FROM invoices
WHERE created_at >= '2024-01-01';
Result: Reports work across all versions. No data migration.
Migration Comparison: Traditional vs PMFA
Traditional ERP (SAP/Oracle/Dynamics)
Small change (add one field):
- Development: 2 weeks
- Testing: 1 week
- Migration script: 3 days
- Production deployment: 4 hours downtime
- Total: 3 weeks + 4h downtime
Medium change (add workflow state):
- Development: 4-6 weeks
- Testing: 2-3 weeks
- Migration script: 1 week
- Production deployment: 8-24 hours downtime
- Total: 2-3 months + 24h downtime
Large change (new approval process):
- Development: 3-6 months
- Testing: 2-3 months
- Migration strategy: 1 month
- Production deployment: 72 hours downtime
- Rollback plan: 1 month
- Total: 6-12 months + 72h downtime
PMFA Platform
Any change:
- Edit YAML meta-model (5-30 minutes)
- Deploy new version (instant)
- Old data continues working
- New data uses new logic
- Total: 5-30 minutes, zero downtime
Cost comparison (3-year project):
| Item | Traditional ERP | PMFA |
|---|---|---|
| Initial development | $500K | $300K |
| Change #1 (year 1) | $80K + 4h downtime | $0 |
| Change #2 (year 1) | $120K + 8h downtime | $0 |
| Change #3 (year 2) | $200K + 24h downtime | $0 |
| Change #4 (year 2) | $150K + 12h downtime | $0 |
| Change #5 (year 3) | $250K + 72h downtime | $0 |
| Total | $1.3M + 120h downtime | $300K + 0h downtime |
Savings: $1M over 3 years + zero business disruption
FAQ: Versioning Strategy
Q: What happens when I have 50 workflow versions?
A: PMFA archives old versions after documents complete:
WorkflowVersionPolicy:
archive_after: 365 days # Archive after 1 year
keep_active: true # Keep for running workflows
delete_after: never # Never delete (audit compliance)
Result: Only active workflows consume runtime memory. Archived versions stored as metadata.
Q: Can I force-migrate old documents to new version?
A: Yes, PMFA provides optional migration tool:
// Migrate specific documents
await pmfa.migrate({
fromVersion: 1,
toVersion: 2,
filter: { status: 'draft' }, // Only draft invoices
transform: (oldDoc) => ({
...oldDoc,
tax_category: 'VAT-20' // Add default value
})
});
Use case: Company policy changes require updating old data.
Q: How do you handle breaking changes?
A: PMFA enforces backward compatibility rules:
BreakingChangePolicy:
allow_field_removal: false # Can't remove fields
allow_type_change: false # Can't change field types
allow_workflow_skip: false # Can't skip required states
If you need breaking change:
- Create new entity type (e.g.,
InvoiceV2) - Run background migration job
- Deprecate old entity after 1 year
Conclusion
Traditional ERP: Migrations are the enemy. Every change = risk + downtime + cost.
PMFA: Versioning eliminates migrations. Deploy changes instantly with zero risk.
The secret: Treat business logic as data, not code. When workflow is YAML, deploying new version is just updating metadata.
Real-world impact:
- 🚀 10x faster deployments (5 minutes vs 3 weeks)
- 💰 90% cost reduction ($0 vs $200K per change)
- ⏱️ Zero downtime (vs 4-72 hours)
- ✅ Zero risk (old workflows keep working)
Want to eliminate migrations from your ERP? Contact us at office@nonnotech.com for a technical demo of PMFA versioning architecture.