🎯 Phase 3 of Programmatic Markdown Generation Refactor
Parent Issue: #73 | Milestone: v2.0 | Type: Breaking Change
📖 Context
opnDossier currently uses Go templates with custom template functions (via Sprig) to generate markdown reports from OPNsense configuration data. While functional, this approach has several limitations:
Current Pain Points
- ⚠️ Runtime errors: Template parsing errors only caught at runtime
- 🐌 Performance overhead: Template parsing adds ~45% execution time
- 🔧 Limited IDE support: No IntelliSense or type checking for template functions
- 🧪 Testing complexity: Difficult to unit test individual template functions
- 📚 Maintenance burden: Dual code paths (template + programmatic)
- 🔍 Debugging difficulty: Template stack traces are cryptic
The Opportunity
By migrating all custom template functions to type-safe Go methods on the MarkdownBuilder, we gain:
- ✅ Compile-time safety: Catch errors during build, not at runtime
- ⚡ Performance: 30-50% faster report generation (no template parsing)
- 🛠️ Developer experience: Full IDE support with IntelliSense and debugging
- 🧪 Testability: Unit test each method independently
- 📦 Maintainability: Single, clean code path
🔍 Current State Analysis
Template Functions Inventory
The codebase currently has 20+ custom template functions in internal/markdown/generator.go:
Utility Functions:
escapeTableContent - Escape markdown table special characters
boolToString - Convert boolean to enabled/disabled
formatBytes - Human-readable byte formatting
truncate - String truncation with ellipsis
sanitizeID - Create markdown-safe IDs
Data Transformation:
filterTunables - Filter system tunables by security relevance
groupServicesByStatus - Group services by running/stopped
filterRulesByType - Filter firewall rules by type
aggregatePackageStats - Calculate package statistics
Security Assessment:
getRiskLevel - Assess and format security risk levels
calculateSecurityScore - Overall security posture scoring
assessServiceRisk - Per-service risk evaluation
Complex Formatters:
formatInterfacesAsLinks - Generate markdown links for interfaces
formatSystemStats - System statistics aggregation
formatNetworkInterfaces - Network interface table formatting
formatFirewallRules - Firewall rule table generation
formatServices - Service status formatting
formatUsers - User account table generation
formatPackages - Package list formatting
formatCertificates - Certificate information display
💡 Proposed Solution
Architecture
┌─────────────────────────────────────────────────────┐
│ OpnSense XML Configuration │
└────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ XML Parser (existing) │
└────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Data Model (model.OpnSenseDocument) │
└────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ MarkdownBuilder (Type-Safe Methods) │
│ ┌────────────────────────────────────────────────┐ │
│ │ • FormatInterfaceLinks() │ │
│ │ • AssessRiskLevel() │ │
│ │ • FilterSystemTunables() │ │
│ │ • CalculateSecurityScore() │ │
│ │ • FormatNetworkInterfaces() │ │
│ │ • (All 20+ methods) │ │
│ └────────────────────────────────────────────────┘ │
└────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Markdown Report Output │
└─────────────────────────────────────────────────────┘
Implementation Strategy
This phase is broken into 10 detailed subtasks for systematic implementation:
📋 Planning & Mapping
🔧 Core Function Migration
✅ Testing & Validation
🚀 Integration & Documentation
Implementation Example
Before (Template):
{{ define "interfaces" }}
## Network Interfaces
Configured: {{ .interfaces | formatInterfacesAsLinks }}
Risk Level: {{ getRiskLevel .security.level }}
{{ end }}
After (Programmatic):
func (b *MarkdownBuilder) WriteInterfacesSection(data *model.OpnSenseDocument) {
b.WriteHeader(2, "Network Interfaces")
interfaceLinks := b.FormatInterfaceLinks(data.Interfaces)
b.WriteParagraph("Configured: " + interfaceLinks)
riskLevel := b.AssessRiskLevel(data.Security.Level)
b.WriteParagraph("Risk Level: " + riskLevel)
}
📅 Implementation Timeline
Week 1: Core Migration
Week 2: Testing & Validation
Week 3: Integration & Documentation
✅ Acceptance Criteria
Functional Requirements
Quality Requirements
Performance Requirements
Documentation Requirements
🎯 Success Metrics
Performance Targets
- Execution Time: 30-50% faster than template mode
- Memory Usage: 20-30% reduction in allocations
- Build Time: Errors caught at compile-time
Quality Targets
- Test Coverage: >90% overall, 100% for security functions
- Bug Reduction: Eliminate runtime template errors
- Developer Velocity: Faster feature development with IDE support
Adoption Targets
- Default Usage: Programmatic mode used by default
- Migration: Clear path for custom template users
- Deprecation: Template mode removed by v3.0
🔗 Dependencies
Prerequisite Phases
- ✅ Phase 1: Core refactoring (assumed complete)
- ✅ Phase 2: Builder infrastructure (assumed complete)
Blocking Issues
- None - ready to begin implementation
Related Work
🏷️ Breaking Changes (v2.0)
⚠️ This is a breaking change for users with custom templates:
-
Default Behavior Change
- Before: Templates used by default
- After: Programmatic generation by default
- Migration: Add
--use-template flag
-
Template Function Removal
- Custom template functions deprecated
- Will be removed in v3.0
- Use
MarkdownBuilder methods instead
-
API Changes
📚 Additional Resources
Note: This issue tracks the overall Phase 3 effort. Implementation work is split across subtasks #89-98. Please reference the appropriate subtask when contributing.
🎯 Phase 3 of Programmatic Markdown Generation Refactor
Parent Issue: #73 | Milestone: v2.0 | Type: Breaking Change
📖 Context
opnDossier currently uses Go templates with custom template functions (via Sprig) to generate markdown reports from OPNsense configuration data. While functional, this approach has several limitations:
Current Pain Points
The Opportunity
By migrating all custom template functions to type-safe Go methods on the
MarkdownBuilder, we gain:🔍 Current State Analysis
Template Functions Inventory
The codebase currently has 20+ custom template functions in
internal/markdown/generator.go:Utility Functions:
escapeTableContent- Escape markdown table special charactersboolToString- Convert boolean to enabled/disabledformatBytes- Human-readable byte formattingtruncate- String truncation with ellipsissanitizeID- Create markdown-safe IDsData Transformation:
filterTunables- Filter system tunables by security relevancegroupServicesByStatus- Group services by running/stoppedfilterRulesByType- Filter firewall rules by typeaggregatePackageStats- Calculate package statisticsSecurity Assessment:
getRiskLevel- Assess and format security risk levelscalculateSecurityScore- Overall security posture scoringassessServiceRisk- Per-service risk evaluationComplex Formatters:
formatInterfacesAsLinks- Generate markdown links for interfacesformatSystemStats- System statistics aggregationformatNetworkInterfaces- Network interface table formattingformatFirewallRules- Firewall rule table generationformatServices- Service status formattingformatUsers- User account table generationformatPackages- Package list formattingformatCertificates- Certificate information display💡 Proposed Solution
Architecture
Implementation Strategy
This phase is broken into 10 detailed subtasks for systematic implementation:
📋 Planning & Mapping
🔧 Core Function Migration
[Phase 3.2] Port utility functions (formatting, escaping, defaults) #90 - [Phase 3.2] Port utility functions (formatting, escaping, defaults)
[Phase 3.3] Port data transformation functions (filtering, aggregation) #91 - [Phase 3.3] Port data transformation functions (filtering, aggregation)
[Phase 3.4] Port security assessment functions (risk levels, scoring) #92 - [Phase 3.4] Port security assessment functions (risk levels, scoring)
✅ Testing & Validation
[Phase 3.5] Create comprehensive test suite for ported methods #93 - [Phase 3.5] Create comprehensive test suite for ported methods
[Phase 3.6] Run performance benchmarks comparing template vs programmatic #94 - [Phase 3.6] Run performance benchmarks comparing template vs programmatic
🚀 Integration & Documentation
[Phase 3.7] Update CLI to use programmatic mode by default #95 - [Phase 3.7] Update CLI to use programmatic mode by default
--use-templateflag[Phase 3.8] Update documentation for programmatic markdown generation #96 - [Phase 3.8] Update documentation for programmatic markdown generation
📘 Complete migration documentation for custom template users (v2.0 breaking change) #97 - [Phase 3.9] Add migration guide for custom template users
Implement Template Mode Deprecation Notices and Migration Tooling for v2.0 #98 - [Phase 3.10] Add deprecation notices for template-only features
Implementation Example
Before (Template):
{{ define "interfaces" }} ## Network Interfaces Configured: {{ .interfaces | formatInterfacesAsLinks }} Risk Level: {{ getRiskLevel .security.level }} {{ end }}After (Programmatic):
📅 Implementation Timeline
Week 1: Core Migration
Week 2: Testing & Validation
Week 3: Integration & Documentation
✅ Acceptance Criteria
Functional Requirements
MarkdownBuildermethods--use-templateflagQuality Requirements
Performance Requirements
Documentation Requirements
🎯 Success Metrics
Performance Targets
Quality Targets
Adoption Targets
🔗 Dependencies
Prerequisite Phases
Blocking Issues
Related Work
🏷️ Breaking Changes (v2.0)
Default Behavior Change
--use-templateflagTemplate Function Removal
MarkdownBuildermethods insteadAPI Changes
📚 Additional Resources
docs/architecture.md(to be updated in [Phase 3.8] Update documentation for programmatic markdown generation #96)Note: This issue tracks the overall Phase 3 effort. Implementation work is split across subtasks #89-98. Please reference the appropriate subtask when contributing.