diff --git a/benchmarks/src/main/java/com/demcha/compose/AllocationRateProbe.java b/benchmarks/src/main/java/com/demcha/compose/AllocationRateProbe.java
index e81c2af92..1d4ad6ac3 100644
--- a/benchmarks/src/main/java/com/demcha/compose/AllocationRateProbe.java
+++ b/benchmarks/src/main/java/com/demcha/compose/AllocationRateProbe.java
@@ -2,10 +2,11 @@
import com.demcha.compose.document.api.DocumentPageSize;
import com.demcha.compose.document.api.DocumentSession;
-import com.demcha.compose.document.templates.builtins.InvoiceTemplateV1;
-import com.demcha.compose.document.templates.builtins.ProposalTemplateV1;
+import com.demcha.compose.document.templates.api.DocumentTemplate;
import com.demcha.compose.document.templates.data.invoice.InvoiceDocumentSpec;
import com.demcha.compose.document.templates.data.proposal.ProposalDocumentSpec;
+import com.demcha.compose.document.templates.invoice.v2.presets.ModernInvoice;
+import com.demcha.compose.document.templates.proposal.v2.presets.ModernProposal;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
@@ -46,9 +47,9 @@ public static void main(String[] args) throws Exception {
enableAllocationMeasurement();
InvoiceDocumentSpec invoice = CanonicalBenchmarkSupport.canonicalInvoice();
- InvoiceTemplateV1 invoiceTemplate = new InvoiceTemplateV1();
+ DocumentTemplate
@@ -56,7 +56,7 @@
public class ColdStartJmhBenchmark {
private InvoiceDocumentSpec invoice;
- private InvoiceTemplateV1 invoiceTemplate;
+ private DocumentTemplate invoiceTemplate;
private CvSpec cv;
private DocumentTemplate cvTemplate;
@@ -64,7 +64,7 @@ public class ColdStartJmhBenchmark {
@Setup
public void setUp() {
invoice = CanonicalBenchmarkSupport.canonicalInvoice();
- invoiceTemplate = new InvoiceTemplateV1();
+ invoiceTemplate = ModernInvoice.create();
cv = CanonicalBenchmarkSupport.canonicalCv();
cvTemplate = ModernProfessional.create(BusinessTheme.modern());
}
@@ -96,7 +96,7 @@ public byte[] coldEngineSimple() throws Exception {
}
/**
- * Cold first render of the canonical invoice through {@code InvoiceTemplateV1}.
+ * Cold first render of the canonical invoice through {@code ModernInvoice}.
*
* @return the rendered PDF bytes (consumed by JMH)
* @throws Exception if rendering fails
diff --git a/examples/README.md b/examples/README.md
index e87e62dbf..ef5a56285 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -127,10 +127,8 @@ are with the canonical DSL, then jump to its detailed section below.
| Example | What it shows | Preview · Source |
|---|---|---|
-| [Invoice (V1)](#invoice-v1) | `InvoiceTemplateV1` driven from `InvoiceDocumentSpec` — pre-rebuild surface, supported only | [PDF](../assets/readme/examples/invoice.pdf) · [Source](src/main/java/com/demcha/examples/templates/invoice/InvoiceFileExample.java) |
-| [Proposal (V1)](#proposal-v1) | `ProposalTemplateV1` driven from `ProposalDocumentSpec` — pre-rebuild surface, supported only | [PDF](../assets/readme/examples/proposal.pdf) · [Source](src/main/java/com/demcha/examples/templates/proposal/ProposalFileExample.java) |
| [Handcrafted Proposal](#handcrafted-proposal) | v1.4-style cinematic proposal composed by hand — pre-template authoring; kept for parity reference | [PDF](../assets/readme/examples/project-proposal-cinematic.pdf) · [Source](src/main/java/com/demcha/examples/templates/proposal/CinematicProposalFileExample.java) |
-| [Weekly schedule](#weekly-schedule) | Bar / restaurant shift schedule via `WeeklyScheduleRenderer` (`WeeklyScheduleTemplateV1` — no V2 yet; will be re-shaped before 2.0) | [PDF](../assets/readme/examples/weekly-schedule.pdf) · [Source](src/main/java/com/demcha/examples/templates/schedule/WeeklyScheduleFileExample.java) |
+| [Weekly schedule](#weekly-schedule) | Bar / restaurant shift schedule via `WeeklyScheduleRenderer` | [PDF](../assets/readme/examples/weekly-schedule.pdf) · [Source](src/main/java/com/demcha/examples/templates/schedule/WeeklyScheduleFileExample.java) |
---
@@ -177,45 +175,6 @@ try (DocumentSession document = GraphCompose.document(outputFile)
[📄 View PDF](../assets/readme/examples/cover-letter.pdf) ·
[📜 Full source](src/main/java/com/demcha/examples/templates/coverletter/CoverLetterFileExample.java)
-### Invoice (V1)
-
-`InvoiceTemplateV1.compose(document, spec)` handles the full layout —
-header band, parties row, line-items table, totals row, payment-terms
-footer — driven from a `InvoiceDocumentSpec`. Use this when you want
-the legacy hard-coded theme; for V2 cinematic, see below.
-
-```java
-InvoiceDocumentSpec spec = InvoiceDocumentSpec.builder()
- .invoiceNumber("GC-2026-041")
- .issueDate("02 Apr 2026")
- .dueDate("16 Apr 2026")
- .fromParty(p -> p.name("GraphCompose Studio"))
- .billToParty(p -> p.name("Northwind Systems"))
- .lineItem("Template architecture", "Reusable invoice flow", "2", "GBP 980", "GBP 1,960")
- .totalRow("Total", "GBP 1,960")
- .build();
-
-try (DocumentSession document = GraphCompose.document(outputFile)
- .pageSize(DocumentPageSize.A4)
- .margin(28, 28, 28, 28)
- .create()) {
- new InvoiceTemplateV1().compose(document, spec);
- document.buildPdf();
-}
-```
-
-[📄 View PDF](../assets/readme/examples/invoice.pdf) ·
-[📜 Full source](src/main/java/com/demcha/examples/templates/invoice/InvoiceFileExample.java)
-
-### Proposal (V1)
-
-`ProposalTemplateV1` rendered against a `ProposalDocumentSpec` —
-sections, scope items, deliverables, sign-off. Pairs naturally with
-`InvoiceTemplateV1` for consistent "spec → PDF" pipelines.
-
-[📄 View PDF](../assets/readme/examples/proposal.pdf) ·
-[📜 Full source](src/main/java/com/demcha/examples/templates/proposal/ProposalFileExample.java)
-
### Module-first profile
Authoring against `DocumentSession.pageFlow().module(...)` — no
diff --git a/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java b/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java
index e566e387a..32b9a2aa5 100644
--- a/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java
+++ b/examples/src/main/java/com/demcha/examples/GenerateAllExamples.java
@@ -80,12 +80,10 @@
import com.demcha.examples.templates.cv.v2.CvSidebarPortraitExample;
import com.demcha.examples.templates.cv.v2.CvTimelineMinimalExample;
import com.demcha.examples.templates.invoice.InvoiceCinematicFileExample;
-import com.demcha.examples.templates.invoice.InvoiceFileExample;
import com.demcha.examples.templates.invoice.v2.ModernInvoiceV2Example;
import com.demcha.examples.templates.proposal.CinematicProposalFileExample;
import com.demcha.examples.templates.proposal.ProposalCinematicFileExample;
import com.demcha.examples.templates.proposal.v2.ModernProposalV2Example;
-import com.demcha.examples.templates.proposal.ProposalFileExample;
import com.demcha.examples.templates.schedule.WeeklyScheduleFileExample;
/**
@@ -138,12 +136,10 @@ public static void main(String[] args) throws Exception {
System.out.println("Generated: " + CvTimelineMinimalLetterV2Example.generate());
// Invoices
- System.out.println("Generated: " + InvoiceFileExample.generate());
System.out.println("Generated: " + InvoiceCinematicFileExample.generate());
System.out.println("Generated: " + ModernInvoiceV2Example.generate());
// Proposals
- System.out.println("Generated: " + ProposalFileExample.generate());
System.out.println("Generated: " + ProposalCinematicFileExample.generate());
System.out.println("Generated: " + ModernProposalV2Example.generate());
System.out.println("Generated: " + CinematicProposalFileExample.generate());
diff --git a/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java b/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java
index 0eb173e60..c7649b02c 100644
--- a/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java
+++ b/examples/src/main/java/com/demcha/examples/support/ShowcaseMetadata.java
@@ -78,11 +78,9 @@ record Entry(String title, String description, List tags, String codeUrl
letter("cover-letter-mint-editorial-v2", "CvMintEditorialLetterV2Example", "Mint Editorial letter", "Letter paired with Mint Editorial CV — magazine-style mint accent.");
// ===== Templates / Invoice =====
- invoice("invoice", "Invoice (canonical)", "Single-page invoice with line items, totals, and structured chrome — InvoiceTemplateV1.", "invoice");
invoice("invoice-cinematic", "Cinematic Invoice", "Polished V2 invoice template with theme-driven layout, advanced tables, and totals.", "invoice", "cinematic");
// ===== Templates / Proposal =====
- proposal("proposal", "Proposal (canonical)", "Multi-section proposal with cover, scope, deliverables, and pricing — ProposalTemplateV1.", "proposal");
proposal("proposal-cinematic", "Cinematic Proposal", "Cinematic V2 proposal layout with cover panel, hero spread, and rich typography.", "proposal", "cinematic");
proposal("project-proposal-cinematic", "Project Proposal (cinematic)", "End-to-end project proposal with mountain hero, scope panels, and pricing summary.", "proposal", "cinematic");
@@ -183,16 +181,13 @@ private static void letter(String id, String exampleClass, String title, String
}
private static void invoice(String id, String title, String desc, String... tags) {
- String file = id.contains("cinematic") ? "InvoiceCinematicFileExample" : "InvoiceFileExample";
ENTRIES.put(id, entry(title, desc, withCategory("invoice", tags),
- EX_BASE + "/templates/invoice/" + file + ".java"));
+ EX_BASE + "/templates/invoice/InvoiceCinematicFileExample.java"));
}
private static void proposal(String id, String title, String desc, String... tags) {
- String file;
- if (id.equals("project-proposal-cinematic")) file = "CinematicProposalFileExample";
- else if (id.contains("cinematic")) file = "ProposalCinematicFileExample";
- else file = "ProposalFileExample";
+ String file = id.equals("project-proposal-cinematic")
+ ? "CinematicProposalFileExample" : "ProposalCinematicFileExample";
ENTRIES.put(id, entry(title, desc, withCategory("proposal", tags),
EX_BASE + "/templates/proposal/" + file + ".java"));
}
diff --git a/examples/src/main/java/com/demcha/examples/templates/invoice/InvoiceFileExample.java b/examples/src/main/java/com/demcha/examples/templates/invoice/InvoiceFileExample.java
deleted file mode 100644
index 6035e5e9e..000000000
--- a/examples/src/main/java/com/demcha/examples/templates/invoice/InvoiceFileExample.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.demcha.examples.templates.invoice;
-
-import com.demcha.compose.GraphCompose;
-import com.demcha.compose.document.api.DocumentPageSize;
-import com.demcha.compose.document.api.DocumentSession;
-import com.demcha.compose.document.templates.builtins.InvoiceTemplateV1;
-import com.demcha.examples.support.ExampleDataFactory;
-import com.demcha.examples.support.ExampleOutputPaths;
-
-import java.nio.file.Path;
-
-public final class InvoiceFileExample {
-
- private InvoiceFileExample() {
- }
-
- public static Path generate() throws Exception {
- Path outputFile = ExampleOutputPaths.prepare("templates/invoice", "invoice.pdf");
- InvoiceTemplateV1 template = new InvoiceTemplateV1();
-
- try (DocumentSession document = GraphCompose.document(outputFile)
- .pageSize(DocumentPageSize.A4)
- .margin(22, 22, 22, 22)
- .create()) {
- template.compose(document, ExampleDataFactory.sampleInvoice());
- document.buildPdf();
- }
-
- return outputFile;
- }
-
- public static void main(String[] args) throws Exception {
- System.out.println("Generated: " + generate());
- }
-}
diff --git a/examples/src/main/java/com/demcha/examples/templates/proposal/ProposalFileExample.java b/examples/src/main/java/com/demcha/examples/templates/proposal/ProposalFileExample.java
deleted file mode 100644
index a4708830b..000000000
--- a/examples/src/main/java/com/demcha/examples/templates/proposal/ProposalFileExample.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.demcha.examples.templates.proposal;
-
-import com.demcha.compose.GraphCompose;
-import com.demcha.compose.document.api.DocumentPageSize;
-import com.demcha.compose.document.api.DocumentSession;
-import com.demcha.compose.document.templates.builtins.ProposalTemplateV1;
-import com.demcha.examples.support.ExampleDataFactory;
-import com.demcha.examples.support.ExampleOutputPaths;
-
-import java.nio.file.Path;
-
-public final class ProposalFileExample {
-
- private ProposalFileExample() {
- }
-
- public static Path generate() throws Exception {
- Path outputFile = ExampleOutputPaths.prepare("templates/proposal", "proposal.pdf");
- ProposalTemplateV1 template = new ProposalTemplateV1();
-
- try (DocumentSession document = GraphCompose.document(outputFile)
- .pageSize(DocumentPageSize.A4)
- .margin(22, 22, 22, 22)
- .create()) {
- template.compose(document, ExampleDataFactory.sampleProposal());
- document.buildPdf();
- }
-
- return outputFile;
- }
-
- public static void main(String[] args) throws Exception {
- System.out.println("Generated: " + generate());
- }
-}
diff --git a/src/main/java/com/demcha/compose/document/templates/api/InvoiceTemplate.java b/src/main/java/com/demcha/compose/document/templates/api/InvoiceTemplate.java
index 3ec59a3fb..2ea737906 100644
--- a/src/main/java/com/demcha/compose/document/templates/api/InvoiceTemplate.java
+++ b/src/main/java/com/demcha/compose/document/templates/api/InvoiceTemplate.java
@@ -11,7 +11,7 @@
* {@link DocumentSession}.
*
* {@code
- * InvoiceTemplate template = new InvoiceTemplateV1();
+ * InvoiceTemplate template = new InvoiceTemplateV2();
* InvoiceDocumentSpec invoice = InvoiceDocumentSpec.builder()
* .invoiceNumber("GC-2026-041")
* .fromParty(party -> party.name("GraphCompose Studio"))
diff --git a/src/main/java/com/demcha/compose/document/templates/api/ProposalTemplate.java b/src/main/java/com/demcha/compose/document/templates/api/ProposalTemplate.java
index 44e45a514..92d153c5a 100644
--- a/src/main/java/com/demcha/compose/document/templates/api/ProposalTemplate.java
+++ b/src/main/java/com/demcha/compose/document/templates/api/ProposalTemplate.java
@@ -11,7 +11,7 @@
* {@link DocumentSession}.
*
* {@code
- * ProposalTemplate template = new ProposalTemplateV1();
+ * ProposalTemplate template = new ProposalTemplateV2();
* ProposalDocumentSpec proposal = ProposalDocumentSpec.builder()
* .projectTitle("GraphCompose rollout")
* .section("Scope", "Introduce reusable invoice and proposal templates.")
diff --git a/src/main/java/com/demcha/compose/document/templates/builtins/InvoiceTemplateV1.java b/src/main/java/com/demcha/compose/document/templates/builtins/InvoiceTemplateV1.java
deleted file mode 100644
index 2f399cfd9..000000000
--- a/src/main/java/com/demcha/compose/document/templates/builtins/InvoiceTemplateV1.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.demcha.compose.document.templates.builtins;
-
-import com.demcha.compose.document.api.DocumentSession;
-import com.demcha.compose.document.templates.api.InvoiceTemplate;
-import com.demcha.compose.document.templates.data.invoice.InvoiceDocumentSpec;
-import com.demcha.compose.document.templates.support.business.BusinessDocumentSceneStyles;
-import com.demcha.compose.document.templates.support.business.InvoiceTemplateComposer;
-import com.demcha.compose.document.templates.support.common.SessionTemplateComposeTarget;
-import com.demcha.compose.document.templates.support.common.TemplateLifecycleLog;
-
-/**
- * Canonical implementation of the invoice template.
- */
-public final class InvoiceTemplateV1 implements InvoiceTemplate {
- private final InvoiceTemplateComposer composer = new InvoiceTemplateComposer(new BusinessDocumentSceneStyles());
-
- /**
- * Creates the canonical invoice template.
- */
- public InvoiceTemplateV1() {
- }
-
- @Override
- public String getTemplateId() {
- return "invoice-v1";
- }
-
- @Override
- public String getTemplateName() {
- return "Invoice V1";
- }
-
- @Override
- public String getDescription() {
- return "A light business invoice template with metadata, billing parties, line items, and totals.";
- }
-
- @Override
- public void compose(DocumentSession document, InvoiceDocumentSpec spec) {
- long startNanos = TemplateLifecycleLog.start(getTemplateId(), spec);
- try {
- composer.compose(new SessionTemplateComposeTarget(document), spec);
- TemplateLifecycleLog.success(getTemplateId(), spec, startNanos);
- } catch (RuntimeException | Error ex) {
- TemplateLifecycleLog.failure(getTemplateId(), spec, startNanos, ex);
- throw ex;
- }
- }
-}
diff --git a/src/main/java/com/demcha/compose/document/templates/builtins/ProposalTemplateV1.java b/src/main/java/com/demcha/compose/document/templates/builtins/ProposalTemplateV1.java
deleted file mode 100644
index 9190bbb45..000000000
--- a/src/main/java/com/demcha/compose/document/templates/builtins/ProposalTemplateV1.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.demcha.compose.document.templates.builtins;
-
-import com.demcha.compose.document.api.DocumentSession;
-import com.demcha.compose.document.templates.api.ProposalTemplate;
-import com.demcha.compose.document.templates.data.proposal.ProposalDocumentSpec;
-import com.demcha.compose.document.templates.support.business.BusinessDocumentSceneStyles;
-import com.demcha.compose.document.templates.support.business.ProposalTemplateComposer;
-import com.demcha.compose.document.templates.support.common.SessionTemplateComposeTarget;
-import com.demcha.compose.document.templates.support.common.TemplateLifecycleLog;
-
-/**
- * Canonical implementation of the proposal template.
- */
-public final class ProposalTemplateV1 implements ProposalTemplate {
- private final ProposalTemplateComposer composer = new ProposalTemplateComposer(new BusinessDocumentSceneStyles());
-
- /**
- * Creates the canonical proposal template.
- */
- public ProposalTemplateV1() {
- }
-
- @Override
- public String getTemplateId() {
- return "proposal-v1";
- }
-
- @Override
- public String getTemplateName() {
- return "Proposal V1";
- }
-
- @Override
- public String getDescription() {
- return "A light business proposal template with executive summary, scope, timeline, pricing, and acceptance terms.";
- }
-
- @Override
- public void compose(DocumentSession document, ProposalDocumentSpec spec) {
- long startNanos = TemplateLifecycleLog.start(getTemplateId(), spec);
- try {
- composer.compose(new SessionTemplateComposeTarget(document), spec);
- TemplateLifecycleLog.success(getTemplateId(), spec, startNanos);
- } catch (RuntimeException | Error ex) {
- TemplateLifecycleLog.failure(getTemplateId(), spec, startNanos, ex);
- throw ex;
- }
- }
-}
diff --git a/src/test/java/com/demcha/documentation/DocumentationExamplesTest.java b/src/test/java/com/demcha/documentation/DocumentationExamplesTest.java
index cd130f84d..14e8c749f 100644
--- a/src/test/java/com/demcha/documentation/DocumentationExamplesTest.java
+++ b/src/test/java/com/demcha/documentation/DocumentationExamplesTest.java
@@ -4,9 +4,9 @@
import com.demcha.compose.document.api.DocumentPageSize;
import com.demcha.compose.document.api.DocumentSession;
import com.demcha.compose.document.image.DocumentImageFitMode;
-import com.demcha.compose.document.templates.api.InvoiceTemplate;
-import com.demcha.compose.document.templates.builtins.InvoiceTemplateV1;
+import com.demcha.compose.document.templates.api.DocumentTemplate;
import com.demcha.compose.document.templates.data.invoice.InvoiceDocumentSpec;
+import com.demcha.compose.document.templates.invoice.v2.presets.ModernInvoice;
import com.demcha.compose.document.style.DocumentColor;
import com.demcha.compose.document.style.DocumentInsets;
import com.demcha.compose.document.style.DocumentStroke;
@@ -163,7 +163,7 @@ void shouldRenderModuleFirstDslExampleToFile() throws Exception {
@Test
void shouldRenderComposeFirstBuiltInTemplateExampleToFile() throws Exception {
Path outputFile = VisualTestOutputs.preparePdf("compose-first-invoice-template", "clean", "documentation");
- InvoiceTemplate template = new InvoiceTemplateV1();
+ DocumentTemplate template = ModernInvoice.create();
try (DocumentSession document = GraphCompose.document(outputFile)
.pageSize(DocumentPageSize.A4)
diff --git a/src/test/java/com/demcha/mock/ProposalDataFixtures.java b/src/test/java/com/demcha/mock/ProposalDataFixtures.java
index 0e8d06b3d..458dd3331 100644
--- a/src/test/java/com/demcha/mock/ProposalDataFixtures.java
+++ b/src/test/java/com/demcha/mock/ProposalDataFixtures.java
@@ -47,14 +47,14 @@ public static ProposalData longProposal() {
repeatSentence("Weekly checkpoints will focus on visual deltas, example ergonomics, and whether the generated outputs are understandable for both library consumers and internal maintainers.", 4),
repeatSentence("Each milestone includes a review of template polish, code readability, and whether the generated examples are strong enough to support README and demo usage.", 4)))),
List.of(
- new ProposalTimelineItem("Week 1", "5 days", "API alignment, DTO modeling, invoice template implementation, and review-ready render tests."),
- new ProposalTimelineItem("Week 2", "5 days", "Proposal template implementation, long-content pagination verification, and examples module setup."),
- new ProposalTimelineItem("Week 3", "3 days", "README refresh, final PDF review, and delivery handoff package.")),
+ new ProposalTimelineItem("Week 1", "5 days", "API alignment, DTO modeling, render tests."),
+ new ProposalTimelineItem("Week 2", "5 days", "Proposal template + pagination checks."),
+ new ProposalTimelineItem("Week 3", "3 days", "README refresh, final review, handoff.")),
List.of(
- new ProposalPricingRow("Foundation", "Public template APIs, DTOs, and cleanup of devtool production scope.", "GBP 3,200", false),
- new ProposalPricingRow("Template delivery", "Invoice and proposal layouts with render tests and polished defaults.", "GBP 4,450", false),
- new ProposalPricingRow("Examples package", "Runnable examples module, sample data, and usage documentation.", "GBP 1,850", false),
- new ProposalPricingRow("Total investment", "Fixed-price delivery for the agreed scope.", "GBP 9,500", true)),
+ new ProposalPricingRow("Foundation", "Public template APIs and cleanup.", "GBP 3,200", false),
+ new ProposalPricingRow("Template delivery", "Invoice and proposal layouts + tests.", "GBP 4,450", false),
+ new ProposalPricingRow("Examples package", "Runnable examples module + docs.", "GBP 1,850", false),
+ new ProposalPricingRow("Total investment", "Fixed-price delivery, agreed scope.", "GBP 9,500", true)),
List.of(
"Proposal pricing is valid until the stated expiration date.",
"Any additional template families beyond the agreed four examples are scoped separately.",