Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ back here.

| You are… | Read |
|---|---|
| **New to GraphCompose** — what is it, how do I render my first PDF | [Getting started](getting-started.md) → [Hello world in root README](../README.md#hello-world) |
| **New to GraphCompose** — what is it, how do I render my first PDF | [Your first document](first-document.md) → [Getting started](getting-started.md) |
| **Author rendering an invoice or proposal** | [Built-in business templates](templates/business-templates.md) |
| **Author rendering a CV** with your own data | [Templates v2 (layered) — quickstart](templates/v2-layered/quickstart.md) |
| **Designer / author** wanting a custom visual style for CVs | [Templates v2 (layered) — authoring presets](templates/v2-layered/authoring-presets.md) |
| **Author using legacy v1.6 templates** (CV / cover-letter / invoice / proposal still using `*Spec` + builders) | [Templates v1-classic — landing](templates/v1-classic/README.md) |
Expand All @@ -26,10 +27,14 @@ back here.
## 📁 By category

### Getting started
- **[first-document.md](first-document.md)** — the five-minute path from an empty project to a rendered PDF.
- **[getting-started.md](getting-started.md)** — DSL vs templates, first-render walk-through, decision tree.
- **[capabilities.md](capabilities.md)** — one-glance map of every feature with its stability tier and guide link.
- **[diagrams.md](diagrams.md)** — visual decision diagrams (authoring path, layout, output, lifecycle).
- **[troubleshooting.md](troubleshooting.md)** — symptom-first fixes for common gotchas: stray `?` glyphs, silent DOCX drops, optional-dependency `NoClassDefFoundError`, running the bundled examples.

### Templates
- **[templates/business-templates.md](templates/business-templates.md)** — built-in invoice & proposal templates: the compose-first contract, end to end.
- **[templates/v2-layered/](templates/v2-layered/)** — 🆕 canonical going-forward pattern (CV is the reference implementation): `data` / `theme` / `components` / `widgets` / `presets`.
- **[templates/v1-classic/](templates/v1-classic/)** — the spec/builder/presets surface used by v1.6 CV, cover-letter, invoice, proposal templates. Still ships, still supported.

Expand Down
89 changes: 89 additions & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Capabilities

A one-glance map of what GraphCompose can do, the main API for each,
and its stability tier. "Stability" rows use the tiers defined in the
[API stability policy](api-stability.md); "Guide" links to the page that
shows it in context.

This is a feature catalogue, not the contract — the
[API stability policy](api-stability.md) is authoritative for what each
tier promises, and [canonical ⇄ legacy parity](architecture/canonical-legacy-parity.md)
tracks what is `Partial` or `Planned`.

---

## Authoring

| Capability | Main API | Stability | Guide |
|---|---|---|---|
| Open a document session | `GraphCompose.document(...)` → `DocumentSession` | Stable | [Your first document](first-document.md) |
| Describe content in reading order | `pageFlow(...)`, `module(...)`, `addSection(...)` | Stable | [Getting started](getting-started.md) |
| Maintained document templates | `InvoiceTemplateV2`, `ProposalTemplateV2`, `cv.v2.*`, `coverletter.v2.*` | Stable | [Templates](templates/which-template-system.md) |
| Reusable building blocks (helpers) | helper methods / widgets over the DSL | Stable | [Diagrams](diagrams.md#choose-your-authoring-path) |
| Custom node / backend | `NodeDefinition`, render-handler SPI, `FixedLayoutBackend` | Extension SPI (`@Beta`) | [Extending](recipes/extending.md) |

## Content

| Capability | Main API | Stability | Guide |
|---|---|---|---|
| Paragraphs & rich inline text | `addParagraph(...)`, `addRich(...)`, `RichText` | Stable | [Recipes — rich text](recipes.md) |
| Lists (flat & nested) | `addList(...)`, `ListBuilder` | Stable | [Recipes](recipes.md) |
| Tables (spans, zebra, totals, repeat header) | `addTable(...)`, `DocumentTableCell` | Stable | [Advanced tables](recipes/tables.md) |
| Raster images | `addImage(...)`, fit modes | Stable | [Shapes & images](recipes/shapes.md) |
| Vector shapes, dividers, lines | `addShape(...)`, `addLine(...)`, `addEllipse(...)` | Stable | [Shapes](recipes/shapes.md) |
| Charts (bar / line / pie) | `chart(ChartSpec...)`, `ChartData` | Stable | [Charts](recipes/charts.md) |
| Barcodes & QR | `addBarcode(...)` | Stable | [Recipes](recipes.md) |

## Layout

| Capability | Main API | Stability | Guide |
|---|---|---|---|
| Columns that still flow | `addRow(row -> row.weights(...))` | Stable | [Layered page design](recipes/layered-page-design.md) |
| Page-wide fills / bands | `pageBackground(...)`, `pageBackgrounds(...)` | Stable | [Page backgrounds](recipes/page-backgrounds.md) |
| Overlap & alignment | `addLayerStack(...)` | Stable | [Layered page design](recipes/layered-page-design.md) |
| Shape-as-container | `addContainer(...)`, `addCircle(...)`, `addEllipse(...)` | Stable | [Shape as container](recipes/shape-as-container.md) |
| Fixed (x, y) placement | `addCanvas(w, h, canvas -> canvas.position(...))` | Stable | [Absolute placement](recipes/absolute-placement.md) |
| Bleed to page edge | `bleedToEdge(...)` | Stable | [Page backgrounds](recipes/page-backgrounds.md) |
| Transforms (rotate / scale) | `DocumentTransform` | Stable | [Transforms](recipes/transforms.md) |

## Output & testing

| Capability | Main API | Stability | Guide |
|---|---|---|---|
| Write a PDF file | `buildPdf()`, `buildPdf(Path)` | Stable | [Getting started](getting-started.md) |
| Stream to a caller-owned stream | `writePdf(OutputStream)` | Stable | [Streaming](recipes/streaming.md) |
| In-memory bytes | `toPdfBytes()` | Stable | [Getting started](getting-started.md) |
| Editable Word (semantic) | `export(new DocxSemanticBackend())` | Stable (semantic, not PDF parity) | [Troubleshooting](troubleshooting.md) |
| PDF chrome (metadata / watermark / header / footer / protection) | `metadata(...)`, `watermark(...)`, `header(...)`, `footer(...)`, `protect(...)` | Stable | [Getting started](getting-started.md) |
| Layout snapshot regression | `LayoutSnapshotAssertions.assertMatches(...)` | Stable | [Layout snapshot testing](operations/layout-snapshot-testing.md) |
| Visual (pixel) regression | `PdfVisualRegression` | Stable | [Layout snapshot testing](operations/layout-snapshot-testing.md) |
| Render-only debug overlays | `guideLines(...)`, `debug(...)` | Stable | [Getting started](getting-started.md#debug-guide-lines) |

## Navigation

| Capability | Main API | Stability | Guide |
|---|---|---|---|
| External links | `addLink(...)`, `inlineLink(...)` | Stable | [Getting started](getting-started.md) |
| Internal jumps | `anchor("x")` + `linkTo("x")` | Stable | [Getting started](getting-started.md) |
| PDF outline bookmarks | `bookmark(new DocumentBookmarkOptions(...))` | Stable | [Getting started](getting-started.md) |

---

## New in 1.9.0

These ship from 1.9.0 onward — confirm your dependency version before relying on them:

| Capability | Main API |
|---|---|
| Printed page references | `addPageReference("anchor")` |
| Generated Table of Contents | `addTableOfContents(toc -> toc.entry(...))` |
| Page preview images | `toImage(pageIndex, dpi)`, `toImages(dpi)` |

---

## See also

- [API stability policy](api-stability.md) — what each tier promises.
- [Decision diagrams](diagrams.md) — visual "which API do I use?".
- [Recipes](recipes.md) — the full cookbook.
- [Which template system should I use?](templates/which-template-system.md) — template-surface decision.
89 changes: 89 additions & 0 deletions docs/diagrams.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Decision Diagrams

Visual versions of the "which API do I reach for?" decisions. Each
diagram renders on GitHub (Mermaid). The prose walkthroughs live in
[Getting started](getting-started.md) and
[Your first document](first-document.md).

---

## Choose your authoring path

Start from intent. Most documents are either a maintained template or a
custom page flow; helpers, layout primitives, and extensions come later.

```mermaid
flowchart TD
A[I want to generate a document] --> B{Known family?<br/>CV / invoice / proposal / cover letter}
B -- Yes --> T[Use a maintained template]
B -- No --> C{Mostly reads top to bottom?}
C -- Yes --> F["GraphCompose.document(...) + pageFlow(...)"]
C -- Needs specific placement --> L["A layout primitive<br/>(row / canvas / shape container)"]
F --> D{Same shape repeats across your app?}
D -- Yes --> H[Extract a helper / widget over the DSL]
D -- No --> Done1[Author the page flow]
H --> Done1
L --> Done2[See the layout diagram below]
T --> Done3[Supply the data spec, then render]
```

---

## Where does content go on the page?

Flow is the default. Reach for a stronger primitive only when the
content has a specific placement relationship.

```mermaid
flowchart TD
A[Place content on the page] --> B{Top-to-bottom reading order?}
B -- Yes --> Flow[pageFlow / sections / modules]
B -- No --> C{Side by side, still part of the flow?}
C -- Yes --> Row["addRow(row -> row.weights(...))"]
C -- No --> D{A fill behind every page?}
D -- Yes --> BG["pageBackground(s)(...)"]
D -- No --> E{Overlap or a framed block?}
E -- Yes --> Layer[Layer stack / shape container]
E -- No --> Canvas["addCanvas(w, h, ...) — exact x/y"]
```

---

## Where does the output go?

Choose the output method by destination. Create one `DocumentSession`
per render request.

```mermaid
flowchart TD
A[The document is built] --> B{Where does it go?}
B -- A file --> F["buildPdf() / buildPdf(path)"]
B -- HTTP / cloud stream --> S["writePdf(OutputStream)"]
B -- A byte array --> Y["toPdfBytes()"]
B -- A preview image --> I["toImage(...) / toImages(...)"]
B -- Editable Word --> D["export(new DocxSemanticBackend())"]
```

---

## Document lifecycle

What happens between your code and the PDF.

```mermaid
flowchart LR
A["GraphCompose.document(...)"] --> B[DocumentSession]
B --> C["pageFlow(...) → semantic nodes"]
C --> D[Layout + pagination]
D --> E[PDF output]
D -. inspect .-> S["layoutSnapshot() (testing)"]
```

---

## See also

- [Getting started](getting-started.md) — the prose decision tree and first render.
- [Your first document](first-document.md) — a five-minute walk-through.
- [Which template system should I use?](templates/which-template-system.md) — the template-surface decision.
- [Capabilities](capabilities.md) — what GraphCompose can do, with stability tiers.
121 changes: 121 additions & 0 deletions docs/first-document.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Your First Document

A five-minute path from an empty project to a real PDF. GraphCompose is
session-first: you open a `DocumentSession`, describe content in reading order
with a page flow, and render. No coordinates, no manual page breaks.

> **Prerequisites:** Java 17+ and the `io.github.demchaav:graph-compose`
> dependency — see the [README install snippet](../README.md#installation).

## The smallest document

Open a session for a file path, add one page flow, render. The engine handles
placement and pagination.

```java
import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentPageSize;
import com.demcha.compose.document.api.DocumentSession;

import java.nio.file.Path;

try (DocumentSession document = GraphCompose.document(Path.of("hello.pdf"))
.pageSize(DocumentPageSize.A4)
.margin(24, 24, 24, 24)
.create()) {

document.pageFlow(page -> page
.module("Summary", module -> module.paragraph("Hello GraphCompose")));

document.buildPdf();
}
```

`GraphCompose.document(path)` configures the output; `create()` returns the
`DocumentSession`. Use try-with-resources so the session is always released, even
if rendering fails. Inside the session, `pageFlow(...)` is the document body:
modules, sections, paragraphs, lists, tables, and rows are added top to bottom.

## A real custom document

The same Flow model scales to a multi-section document. There are still no
coordinates and no manual page breaks — just structure in reading order.

```java
import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentPageSize;
import com.demcha.compose.document.api.DocumentSession;

import java.nio.file.Path;

try (DocumentSession document = GraphCompose.document(Path.of("profile.pdf"))
.pageSize(DocumentPageSize.A4)
.margin(24, 24, 24, 24)
.create()) {

document.pageFlow()
.name("CandidateProfile")
.spacing(12)
.module("Professional Summary", module -> module.paragraph(
"Backend engineer focused on clean Java APIs, stable document "
+ "output, and reusable template architecture."))
.module("Technical Skills", module -> module.bullets(
"Java 21 and Spring Boot",
"PDF document generation with GraphCompose",
"Layout snapshot testing and render regression checks"))
.module("Projects", module -> module.rows(
"GraphCompose - declarative document layout engine.",
"CVRewriter - profile-aware CV tailoring platform."))
.build();

document.buildPdf();
}
```

The callback form (`pageFlow(page -> ...)`) builds and attaches the root for you.
The builder form (`pageFlow().…build()`) gives you the fluent chain but you must
call `.build()` yourself.

## Already a known document? Use a template

If your document is a known family — invoice, proposal, CV, cover letter — do not
hand-build it. A maintained template maps a typed data object into the same
session, then you render as usual:

```java
import com.demcha.compose.document.templates.builtins.InvoiceTemplateV2;
import com.demcha.compose.document.theme.BusinessTheme;

InvoiceTemplateV2 template = new InvoiceTemplateV2(BusinessTheme.modern());

try (DocumentSession document = GraphCompose.document(Path.of("invoice.pdf")).create()) {
template.compose(document, invoice); // invoice = your InvoiceDocumentSpec
document.buildPdf();
}
```

Templates and hand-written Flow compose into the *same* `DocumentSession`, so you
can mix them. To choose a template surface, see
[Which template system should I use?](templates/which-template-system.md).

## Rendering on a server

When the caller already owns the output stream — an HTTP response, a cloud
upload — create the session *without* a default path and stream the PDF with
`writePdf(OutputStream)` instead of `buildPdf()`. GraphCompose writes the
stream but does not close it. For the full server snippet, see
[Getting started — Streaming output](getting-started.md#streaming-output).

Create one `DocumentSession` per render request; it is mutable and not
thread-safe. Use `toPdfBytes()` only when the caller truly needs a byte array.

## Where to go next

- [Getting Started](getting-started.md) — themes, hero blocks, layer stacks,
shape-as-container, and built-in templates.
- [Recipes](recipes.md) — themes, shapes, transforms, tables, and layout
snapshots.
- [Which template system should I use?](templates/which-template-system.md) —
the decision tree for CV / invoice / proposal surfaces.
- [Production Rendering](operations/production-rendering.md) — server-side
lifecycle, streaming, and load guidance.
2 changes: 2 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ with `writePdf(...)`, `buildPdf()`, or `toPdfBytes()`.

> **Prerequisites:** Java 17+ and the `io.github.demchaav:graph-compose` dependency — see the [README install snippet](../README.md#installation).

> **New to GraphCompose?** Start with [Your First Document](first-document.md) — a five-minute, copy-paste path from an empty project to a rendered PDF, then come back here for themes, layer stacks, and built-in templates.

## Templates vs DSL — pick the right starting point

GraphCompose has two layers a caller can target. Use this decision
Expand Down
Loading
Loading