-
Notifications
You must be signed in to change notification settings - Fork 0
Home
A Complete Reference Guide (All Features & Architecture)
- Overview
- Core Feature Matrix
- Architecture
- Data Model
- Controls
- Expressions
- Conditional Logic
- Repeaters & Repeating Sections
- Styling (StyleJson)
- Dynamic DOCX Content Controls (SDTs)
- Document Generation Modes
- Conversion (HTML → Dynamic Controls)
- Batch Generation & Job Queue
- Security & Hardening
- API Reference
- Frontend Authoring Experience
- Performance & Caching
- Extensibility Points
- Troubleshooting
- Roadmap
- Usage Examples
- Cheat Sheet
- Limitations & Future Enhancements
- Contributing
- License
A full-featured .NET + React platform for designing and generating Microsoft Word documents:
- Author templates driven by XSD-defined data structures.
- Insert structured controls (TextBox, CheckBox, Grid, Repeater, etc.).
- Use powerful expression filters, array indexing, and conditional logic.
- Implement real Word content controls (SDTs), including true w14 repeatingSection elements.
- Support loop metadata in repeaters:
index,count,first,last,odd,even. - Provide styling via JSON (StyleJson → Run/Paragraph properties).
- Convert legacy HTML token templates → dynamic SDTs.
- Run high-volume background batch generation with job tracking.
| Category | Capabilities |
|---|---|
| Data Schema | XSD ingestion + cached parsing |
| Controls | TextBox, TextArea, CheckBox, RadioGroup, Grid, Repeater |
| Expressions | Filters, formatting, array indexing, relative paths |
| Repeaters | Inline blocks + real Word repeating sections |
| Conditional Logic |
if /path, multi-elseif, else, end nesting |
| Loop Metadata |
index, zeroIndex, first, last, odd, even, count
|
| Styling | StyleJson → Run/Paragraph → Word output |
| Dynamic DOCX | Auto-built SDT doc, optional attach as base |
| Conversion | HTML tokens → control metadata + base DOCX |
| Batch Processing | Background queue, correlation polling |
| Security | JWT auth, input sanitization, size limits |
| Extensibility | Pluggable parsers, evaluators, builders |
| Tests | NUnit coverage for core subsystems |
React Frontend
├─ XSD Tree (drag & drop)
├─ Template Editor (HTML + control markers)
├─ Toolbox (control insertion)
├─ Properties Panel (metadata & styling)
└─ Batch & Conversion Actions
|
v
.NET 8 Web API
├─ XSD Parser & Cache
├─ Expression + Filter Engine
├─ Conditional & Repeater Processors
├─ Style Renderer
├─ Dynamic DOCX Builder (SDTs + w14 repeating sections)
├─ HTML → Control Converter
├─ Generation Orchestrator
├─ Batch Worker (background)
└─ Dapper Repositories
|
v
SQL Server
├─ Templates / Controls / Bindings
├─ XSDs
├─ BaseDocxTemplates
├─ DocumentGenerationJobs
Single Generate:
- Load Template + (optional) BaseDocx.
- Expand Repeaters → Evaluate Conditionals → Replace Expressions.
- Apply Grid/Repeater expansions / fill SDTs.
- Return DOCX.
Batch:
- Enqueue array of JSON payloads.
- Worker locks pending job → processes → stores result.
- Poll correlation ID for statuses & downloads.
| Entity | Purpose |
|---|---|
| XsdDescriptor | Raw XSD + parsed hierarchical tree |
| Template | Core template; HTML body + control list |
| TemplateControl | One logical control (type + data path + style) |
| TemplateControlBinding | Column for Grid/Repeater |
| BaseDocxTemplate | Stored binary DOCX with SDTs |
| DocumentGenerationJob | Batch processing record |
Template 1 --- * TemplateControl 1 --- * TemplateControlBinding
Template 0..1 --- BaseDocxTemplate
Template 1 --- * DocumentGenerationJob
| Table | Notes |
|---|---|
| Templates | Name, HtmlBody, BaseDocxTemplateId |
| TemplateControls | Control metadata & styling |
| TemplateControlBindings | Per-column mapping |
| BaseDocxTemplates | Binary docx storage |
| DocumentGenerationJobs | Batch processing lifecycle |
| Xsds | Original uploaded XSD definitions |
| Type | Description | Core Use |
|---|---|---|
| TextBox | Simple value token | Names, codes |
| TextArea | Multi-line text | Descriptions, notes |
| CheckBox | Boolean representation | Flags |
| RadioGroup | Enum choice | Status categories |
| Grid | Structured table | Multi-column datasets |
| Repeater | Flexible repeating content | Narrative lists |
| Aspect | Grid | Repeater |
|---|---|---|
| Layout | Rigid table | Flexible (table or inline) |
| Columns | Mandatory | Optional (bindings for table) |
| RepeatingSection | Yes | Yes |
| Inline block syntax | No (table only) | Yes (repeat block) |
| Field | Purpose |
|---|---|
| ControlType | Behavior category |
| DataPath | Absolute (or collection path) |
| Label | Display / alias |
| Format | Optional formatting hint |
| OptionsJson | RadioGroup choices / extended settings |
| Bindings | Grid/Repeater columns |
| IsRequired | UI validation hint |
| DefaultValue | Fallback (not auto-applied yet) |
| Width | Editor layout hint |
| StyleJson | Visual styling (Word run/paragraph) |
- Each option becomes its own SDT; group tag encodes base identity.
- Selection logic can be extended to mark chosen value during generation.
{{ /Absolute/Path }}
{{ /Path | date:yyyy-MM-dd }}
{{ /Orders/Order[0]/Total | number:#,##0.00 | upper }}
| Filter | Example | Output |
|---|---|---|
| date | ` | date:yyyy-MM-dd` |
| number | ` | number:#,##0.00` |
| bool | ` | bool:Yes:No` |
| upper | ` | upper` |
| lower | ` | lower` |
| trim | ` | trim` |
Use bracketed zero-based indexes:
/Orders/Order[0]/Items[2]/Sku
Out-of-range → empty result.
-
Absolute: Start with
/, always from root JSON. -
Relative: No leading
/, resolved within current repeater context item.
{{ if /Customer/IsPremium }}
Premium
{{ elseif /Customer/Trial }}
Trial
{{ else }}
Standard
{{ end }}
Supports multiple elseif blocks and nesting.
| Type | Truthy When |
|---|---|
| String | Non-empty |
| Number | Non-zero |
| Boolean | True |
| Array | Length > 0 |
| Object | Has properties |
| Null/Undefined | False |
{{ repeat /Orders/Order }}
{{ index }}: {{ OrderNumber }} - {{ Total | number:#,##0.00 }}
{{ endrepeat }}
| Token | Meaning |
|---|---|
| index | 1-based index |
| zeroIndex | 0-based index |
| first | true if first element |
| last | true if last element |
| odd | true if iteration is odd |
| even | true if iteration even |
| count | Total items |
Allowed; recursion guard prevents infinite loops.
- Controls with repeating behavior (Grid/Repeater) emitted as:
-
w:sdtwithw14:repeatingSection - Nested
w14:repeatingSectionItem
-
- Improves editor UX inside Word (duplicate item UI).
| Key | Scope | Description |
|---|---|---|
| fontSize | Run | e.g. "11pt" |
| bold | Run | true/false |
| italic | Run | true/false |
| underline | Run | true/false |
| color | Run | Hex foreground |
| backgroundColor | Run | Hex shading |
| alignment | Paragraph | left/center/right/justify |
| spacingBefore | Paragraph | Points (numeric) |
| spacingAfter | Paragraph | Points |
- Parse JSON → produce RunProperties / ParagraphProperties.
- Attach to textual runs & paragraphs in SDT.
- Repeating sections replicate styled template row.
<controlId>|<ControlType>|<DataPath>
Repeating section:
<controlId>|Repeat|<CollectionPath>
Radio group option:
<controlId>|RadioGroup|<DataPath>|<index>|<OptionText>
w:sdt
w:sdtPr
w:tag (ctrlId|Repeat|/Collection/Path)
w14:repeatingSection
w:sdtContent
w:sdt
w:sdtPr
w14:repeatingSectionItem
w:sdtContent
(table template row with token placeholders)
- Repeater expansion
- Conditional evaluation
- Expression replacement
- Append Grid/Repeater tables
- Build or load base DOCX with SDTs.
- Replace SDT content via tags (data paths).
- Expand repeating sections.
- Post-process any residual expressions.
- Prototype with HTML → Convert → Attach dynamic base → Continue with structured control editing.
Endpoint:
POST /api/templates/{id}/convert-html-to-dynamic
{
"attachAsBase": true
}
Behavior:
- Scans
{{ /Absolute/Path }}tokens. - Infers control types (simple heuristic).
- Adds missing controls.
- Optionally generates and attaches dynamic DOCX as base.
Enqueue:
POST /api/BatchGeneration/enqueue
{
"templateId": "GUID",
"dataArray": [ { ... }, { ... } ],
"BatchGroup": "RunName"
}
Poll correlation:
GET /api/BatchGeneration/correlation/{correlationId}
Download:
GET /api/BatchGeneration/{jobId}/result
| Step | Action |
|---|---|
| Acquire | Locks Pending job |
| Process | Merge template + data |
| Store | Write DOCX → mark Completed |
| Failure | Capture error & mark Failed |
| Concern | Mechanism |
|---|---|
| Auth | JWT Bearer |
| HTML Safety | Sanitization (allow minimal attributes) |
| Request Size | 20MB limit |
| Path Safety | Strict regex+structure checks |
| XSD Performance | Cached parse |
| Area | Suggestion |
|---|---|
| Rate Limiting | Protect from brute force |
| Tenant Isolation | Add TenantId to all tables |
| Audit Logging | Track template edits & generations |
| Secrets | Externalized key management |
| Webhooks | Job completion notifications |
| Method | Path | Description |
|---|---|---|
| GET | /api/templates | List templates |
| GET | /api/templates/{id} | Get template |
| POST | /api/templates | Create/update |
| GET | /api/templates/{id}/export-dynamic-docx | Build dynamic DOCX |
| POST | /api/templates/{id}/convert-html-to-dynamic | Convert + optional attach |
| Method | Path | Description |
|---|---|---|
| POST | /api/xsd | Upload XSD |
| GET | /api/xsd/{id} | Retrieve parsed tree |
| Method | Path | Description |
|---|---|---|
| POST | /api/BaseDocxTemplates/upload | Upload base docx |
| GET | /api/templates/{id}/export-dynamic-docx | Dynamic build |
| Method | Path | Description |
|---|---|---|
| POST | /api/generate | Single document generation |
| Method | Path | Description |
|---|---|---|
| POST | /api/BatchGeneration/enqueue | Enqueue array |
| GET | /api/BatchGeneration/correlation/{cid} | Correlation status |
| GET | /api/BatchGeneration/{jobId} | Job details |
| GET | /api/BatchGeneration/{jobId}/result | DOCX download |
| Method | Path | Description |
|---|---|---|
| POST | /api/templates/{id}/convert-html-to-dynamic | HTML → controls |
| Panel | Role |
|---|---|
| XSD Tree | Drag paths to create controls |
| Editor | HTML tokens + visual markers |
| Toolbox | Insert control types |
| Properties | Set label, data path, styling, columns |
| Actions | Save, Convert, Export, Batch enqueue |
Drag heuristic:
- Array node → Repeater or Grid
- Boolean → CheckBox
- Other → TextBox
| Layer | Strategy |
|---|---|
| XSD Parsing | IMemoryCache keyed by hash |
| Expression Eval | On-demand (future AST caching) |
| Batch Jobs | Efficient row locking |
| Output | (Future) Template+data hash caching |
| Concern | Interface/Class |
|---|---|
| Expressions |
IExpressionParser, IExpressionEvaluator
|
| Repeaters | IRepeaterBlockProcessor |
| Conditionals | IConditionalBlockProcessor |
| Styling | StyleRenderer |
| DOCX Build | DynamicDocxBuilderService |
| HTML Convert | HtmlToDynamicConverter |
| Batch Queue | IDocumentJobQueue |
| Persistence | Repositories (swap for EF Core, etc.) |
Adding a filter → Extend ApplyFilter.
Adding a control → Update model, builder, UI, and generation pipeline.
| Symptom | Root Cause | Action |
|---|---|---|
| Empty token | Wrong path | Verify JSON keys |
| Missing rows | Path not array | Inspect structure |
| Condition ignored | Path falsey | Log raw JSON |
| Style not applied | Malformed StyleJson | Validate JSON |
| Batch stuck | Worker not active | Check logs & signals |
| Slow generation | Deep nesting / large arrays | Split workloads |
Guards:
- Conditional passes limit (~3000)
- Repeater recursion limit (~1000)
- Request size limit (20MB)
| Phase | Feature |
|---|---|
| Near | Math/string filters, ZIP correlation download |
| Mid | Reverse DOCX → JSON, includes/partials, AST caching |
| Long | Collaborative editing, PDF export, plugin ecosystem |
| Stretch | AI-assisted mapping, conditional styling rules |
{{ /Invoice/IssueDate | date:dd MMM yyyy }}
{{ /Invoice/Total | number:#,##0.00 }}
{{ /Customer/IsPremium | bool:Yes:No }}
{{ repeat /Invoice/Lines/Line }}
{{ index }} / {{ count }}: {{ Description }} = {{ Amount | number:#,##0.00 }}
{{ if DiscountApplied }}(Discount){{ elseif Special }}(Special){{ end }}
{{ endrepeat }}
{{ if /Status/Open }}Open
{{ elseif /Status/InProgress }}In Progress
{{ elseif /Status/Closed }}Closed
{{ else }}Unknown
{{ end }}
{
"fontSize": "11pt",
"bold": true,
"color": "#2E74B5",
"alignment": "center",
"spacingBefore": "6",
"spacingAfter": "6"
}| Task | Action |
|---|---|
| Upload XSD | POST /api/xsd |
| List Templates | GET /api/templates |
| Save Template | POST /api/templates |
| Convert HTML → Dynamic | POST /api/templates/{id}/convert-html-to-dynamic |
| Export Dynamic DOCX | GET /api/templates/{id}/export-dynamic-docx |
| Generate Single DOCX | POST /api/generate |
| Enqueue Batch | POST /api/BatchGeneration/enqueue |
| Poll Batch | GET /api/BatchGeneration/correlation/{cid} |
| Download Job Output | GET /api/BatchGeneration/{jobId}/result |
Loop Metadata: index, zeroIndex, first, last, odd, even, count
Conditional: if /path ... elseif /path ... else ... end
Repeater: {{ repeat /Collection/Items }} ... {{ endrepeat }}
| Area | Current State | Enhancement |
|---|---|---|
| Reverse Merge | Not implemented | Parse SDTs back to JSON |
| Advanced Filters | Limited set | Add math & string ops |
| Partial Templates | Absent | Include/import mechanism |
| Multi-Tenant | Not enforced | Tenant scoping of templates |
| RadioGroup Selection | Manual | Auto data-based selection logic |
| PDF Export | Missing | Integrate transform engine |
| Large Repeats | In-memory expansion | Streamed or paginated output |
- Fork & branch.
- Implement feature with tests.
- Follow existing coding patterns.
- Submit PR with detailed description and (if UI) screenshots.
Add a LICENSE file (e.g., MIT) before public distribution.
- OpenXML SDK for DOCX manipulation.
- NUnit for robust test coverage.
- Community patterns for token templating & expression evaluation.
Happy Templating! Have a feature request? Consult the Roadmap first, then contribute or open a structured issue.