feat(templates): add the structured proposal document model - #609
Merged
DemchaAV merged 1 commit intoAug 30, 2026
Merged
Conversation
The proposal family's data layer knew one shape - a titled run of prose sections with a flat timeline and pricing list - which cannot carry the structured business proposal: brand marks, an authored multi-line title, an at-a-glance fact card, goal cells, a numbered scope list, authored deliverable columns, a phase grid with its own headers, priced rows with a Role (NONE / SUBTOTAL / OPTIONAL) and a total band, and a signing card. templates.data.proposal now carries that second model - StructuredProposalData (+ its section records) wrapped by StructuredProposalDocumentSpec - alongside the narrative one; a preset consumes the model whose shape it renders. Every component normalizes null to its empty form and freezes its collections, matching the family's existing records.
| /** | ||
| * Normalizes optional fields and freezes both columns. | ||
| */ | ||
| public ProposalDeliverables { |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The proposal family's data layer carries one shape —
ProposalData's titled prose sections with a flat timeline and pricing list. The structured business proposal look (brand marks, an authored multi-line title, an at-a-glance fact card, goal cells, a numbered scope list, authored deliverable columns, a phase grid with its own headers, priced rows with roles, a signing card) cannot be represented in it — and bothProposalDataandProposalDocumentSpecare records, so the existing model cannot grow those structures compatibly.What changed
templates.data.proposalgains a second, structured document model beside the narrative one:StructuredProposalData(fluent builder, 12 components) wrapped by the thinStructuredProposalDocumentSpeccarrier (from()), plus the section records —ProposalBrand,ProposalTitleLines(lead/second/third),ProposalMetaLine,ProposalSummaryBlock,ProposalGlance(+Factwith icon/label/value/optional note),ProposalGoals(+Goal),ProposalScope(+numberedItem),ProposalDeliverables(two authored columns),ProposalPhaseGrid(+Phase, headers as an authored list — the column set belongs to the preset that draws the grid, unlikeProposalInvestment, whose two columns are fixed by the concept and therefore named fields),ProposalInvestment(+Rowwith aRole:NONE/SUBTOTAL/OPTIONAL— named for what the row is, not how it looks — and a total band),ProposalTermsBlock,ProposalAcceptance(statement + signature field labels).ProposalScope.ItemvsProposalSection(numbered title+description row vs titled prose run),ProposalPhaseGrid.PhasevsProposalTimelineItem(number/focus/output columns + grid-owned headers vs phase/duration/details triple),ProposalInvestment.RowvsProposalPricingRow(row roles + separate total band vs flat list).null→""/List.of(),Role.NONE),List.copyOffreeze on all 11 collections, no rendering/DSL/Jackson dependencies, every public member documented, largest file 247 LOC. The section records construct positionally; the top-level builder is where a document is assembled.package-infonow names both models and which presets consume which. The narrative model is untouched.northline-proposallook) follows in its own PR, with a second variant of the same look behind it.Verification
./mvnw -B -ntp verify -pl :graph-compose-templates→ BUILD SUCCESS, 111 tests green, +7 new (StructuredProposalDataTest: empty-form normalization for all 12 components, null-string sweep across the leaf records and every section's heading/icon,Roledefault, frozen-collection sweep across all 11 lists, full builder pass-through, spec normalization +from());javadoc:javadoc -pl :graph-compose-templates→ 0 warnings. Additive public API only — no existing type changed.Lane: canonical (templates.data.proposal) — additive data-layer API; no engine changes.