From 3f639f68e0d7554f57ce218282ee08ba92767098 Mon Sep 17 00:00:00 2001 From: DemchaAV Date: Mon, 29 Jun 2026 21:24:16 +0100 Subject: [PATCH 1/2] refactor(templates): remove the V1 invoice/proposal builtins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InvoiceTemplateV1 and ProposalTemplateV1 are pre-rebuild builtins superseded by the layered v2 presets (ModernInvoice / ModernProposal), which render the same InvoiceDocumentSpec / ProposalDocumentSpec. They still had live consumers, so de-consume before deleting. Delete the two V1 builtins and the two V1-only file examples. Repoint the three benchmarks (AllocationRateProbe, CurrentSpeedBenchmark, ColdStartJmhBenchmark) and the documentation example test onto ModernInvoice/ModernProposal — the benchmarks now exercise the v2 presets (the workload renderer changes, so absolute numbers shift). Clean the dropped examples out of GenerateAllExamples, ShowcaseMetadata, and the examples README, and point the surviving InvoiceTemplate/ProposalTemplate Javadoc snippets at the V2 implementer. Tests: ./mvnw verify javadoc:javadoc -pl . — 1621 tests, 0 failures, javadoc gate clean; examples and benchmarks compile against the new jar. --- .../demcha/compose/AllocationRateProbe.java | 9 ++-- .../demcha/compose/CurrentSpeedBenchmark.java | 8 +-- .../compose/jmh/ColdStartJmhBenchmark.java | 10 ++-- examples/README.md | 43 +--------------- .../demcha/examples/GenerateAllExamples.java | 4 -- .../examples/support/ShowcaseMetadata.java | 11 ++--- .../templates/invoice/InvoiceFileExample.java | 35 ------------- .../proposal/ProposalFileExample.java | 35 ------------- .../templates/api/InvoiceTemplate.java | 2 +- .../templates/api/ProposalTemplate.java | 2 +- .../templates/builtins/InvoiceTemplateV1.java | 49 ------------------- .../builtins/ProposalTemplateV1.java | 49 ------------------- .../DocumentationExamplesTest.java | 6 +-- 13 files changed, 23 insertions(+), 240 deletions(-) delete mode 100644 examples/src/main/java/com/demcha/examples/templates/invoice/InvoiceFileExample.java delete mode 100644 examples/src/main/java/com/demcha/examples/templates/proposal/ProposalFileExample.java delete mode 100644 src/main/java/com/demcha/compose/document/templates/builtins/InvoiceTemplateV1.java delete mode 100644 src/main/java/com/demcha/compose/document/templates/builtins/ProposalTemplateV1.java 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 invoiceTemplate = ModernInvoice.create(); ProposalDocumentSpec proposal = CanonicalBenchmarkSupport.canonicalProposal(); - ProposalTemplateV1 proposalTemplate = new ProposalTemplateV1(); + DocumentTemplate proposalTemplate = ModernProposal.create(); System.out.println("GraphCompose allocation-rate / GC-pressure probe (" + MEASURE + " warm renders each)"); System.out.printf("%-12s | %14s | %10s | %12s | %12s%n", diff --git a/benchmarks/src/main/java/com/demcha/compose/CurrentSpeedBenchmark.java b/benchmarks/src/main/java/com/demcha/compose/CurrentSpeedBenchmark.java index 46706038a..499800b8f 100644 --- a/benchmarks/src/main/java/com/demcha/compose/CurrentSpeedBenchmark.java +++ b/benchmarks/src/main/java/com/demcha/compose/CurrentSpeedBenchmark.java @@ -13,12 +13,12 @@ import com.demcha.compose.document.style.DocumentTextStyle; import com.demcha.compose.document.svg.SvgIcon; import com.demcha.compose.document.templates.api.DocumentTemplate; -import com.demcha.compose.document.templates.builtins.InvoiceTemplateV1; -import com.demcha.compose.document.templates.builtins.ProposalTemplateV1; import com.demcha.compose.document.templates.cv.presets.ModernProfessional; import com.demcha.compose.document.templates.cv.spec.CvSpec; 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 com.demcha.compose.document.theme.BusinessTheme; import com.demcha.compose.engine.components.style.Margin; import org.apache.pdfbox.pdmodel.common.PDRectangle; @@ -85,9 +85,9 @@ public final class CurrentSpeedBenchmark { .color(DocumentColor.of(new Color(58, 69, 84))) .build(); - private final InvoiceTemplateV1 invoiceTemplate = new InvoiceTemplateV1(); + private final DocumentTemplate invoiceTemplate = ModernInvoice.create(); private final DocumentTemplate cvTemplate = ModernProfessional.create(BusinessTheme.modern()); - private final ProposalTemplateV1 proposalTemplate = new ProposalTemplateV1(); + private final DocumentTemplate proposalTemplate = ModernProposal.create(); private final InvoiceDocumentSpec invoice = CanonicalBenchmarkSupport.canonicalInvoice(); private final ProposalDocumentSpec proposal = CanonicalBenchmarkSupport.canonicalProposal(); private final CvSpec cv = CanonicalBenchmarkSupport.canonicalCv(); diff --git a/benchmarks/src/main/java/com/demcha/compose/jmh/ColdStartJmhBenchmark.java b/benchmarks/src/main/java/com/demcha/compose/jmh/ColdStartJmhBenchmark.java index a21e3ddbc..6504c8a6f 100644 --- a/benchmarks/src/main/java/com/demcha/compose/jmh/ColdStartJmhBenchmark.java +++ b/benchmarks/src/main/java/com/demcha/compose/jmh/ColdStartJmhBenchmark.java @@ -5,10 +5,10 @@ import com.demcha.compose.document.api.DocumentPageSize; import com.demcha.compose.document.api.DocumentSession; import com.demcha.compose.document.style.DocumentInsets; -import com.demcha.compose.document.templates.builtins.InvoiceTemplateV1; import com.demcha.compose.document.templates.cv.presets.ModernProfessional; import com.demcha.compose.document.templates.cv.spec.CvSpec; import com.demcha.compose.document.templates.data.invoice.InvoiceDocumentSpec; +import com.demcha.compose.document.templates.invoice.v2.presets.ModernInvoice; import com.demcha.compose.document.theme.BusinessTheme; import com.demcha.compose.document.templates.api.DocumentTemplate; import org.openjdk.jmh.annotations.Benchmark; @@ -37,7 +37,7 @@ * reported number is a distribution of cold first-renders, not one lucky start. * The spec/template objects are built in {@link #setUp()} so the measured shot is * the cold render path, not fixture assembly. Same workloads as the warm benches - * ({@code engine-simple} inline, {@code InvoiceTemplateV1}, {@code ModernProfessional}) + * ({@code engine-simple} inline, {@code ModernInvoice}, {@code ModernProfessional}) * so cold and warm numbers are directly comparable.

* *
@@ -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)

From 515228b1a503d5db79973025572735945d98278a Mon Sep 17 00:00:00 2001
From: DemchaAV 
Date: Mon, 29 Jun 2026 21:58:20 +0100
Subject: [PATCH 2/2] fix(benchmarks): trim canonical proposal table cells to
 fit A4

ModernProposal sizes its timeline and pricing description columns to their
content with no wrap, so once the proposal benchmark moved onto the v2
preset the long-form fixture overflowed the page ("Table ProposalTimeline
width 826.5 exceeds available 551.3") and failed the perf-smoke run.

Shorten the timeline and pricing-row descriptions in the benchmark proposal
fixture so both tables fit A4 at the benchmark's 22pt margin. The long
section paragraphs that drive the multi-page pagination workload are
unchanged, so the benchmark still exercises long content. longProposal()
has no other live consumer (canonicalProposalData() is uncalled; the v2
parity test builds its own data).

Tests: ./mvnw -f benchmarks/pom.xml -DskipTests exec:java
-Dexec.mainClass=com.demcha.compose.CurrentSpeedBenchmark
-Dgraphcompose.benchmark.profile=smoke now renders invoice/cv/proposal
(BUILD SUCCESS); engine verify + benchmark gates green.
---
 .../java/com/demcha/mock/ProposalDataFixtures.java | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

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.",