← Back to PDF publishing
UX Specification

PDF publishing

UX Specification AzDO #4035

PDF Publishing — UX Specification

0382026-05-17
Contents
  1. 1. Feature Placement in the IA
  2. 2. Route Map (New Routes)
  3. 3. Admin Screens (Admin Portal)
  4. 4. Author Screens (Platform App)
  5. 5. No Stylesheets Configured (Author-Facing)
  6. 6. User Flows
  7. 7. State Machine — Publish Job Lifecycle
  8. 8. Capability Gating
  9. 9. Loading & Skeleton States
  10. 10. Error States
  11. 11. Responsive Behavior
  12. 12. Accessibility Considerations
  13. 13. Integration with Existing Patterns
  14. 14. URL State Conventions
  15. 15. Admin Tool Navigation Integration
  16. 16. Design Decisions & Rationale

PDF Publishing — UX Specification

Feature: PDF Publishing (spec 038)

Document type: UX Specification & Wireframes

Audience: UX review, frontend developers, product

Date: 2026-05-17

Reference spec: spec.md

Reference IA: Information Architecture (ux-spec prompt)


1. Feature Placement in the IA

PDF Publishing spans two distinct applications:

| Surface | Application | Who | What they do |
|---------|-------------|-----|-------------|
| **Admin Portal** (separate web app) | Platform Admin Portal (`/c/:customerId/ws/:workspaceId/...`) | Workspace administrators | Manage stylesheets, variants, templates, revision history, basic styling, view all workspace jobs |
| **Author View / Object context** | Platform App (`/ws/:workspaceId/...`) | Authors | Initiate publish, select variant, monitor jobs, download PDFs |

The Admin Portal is a separate frontend application that communicates with the AdminAPI microservice. It uses a collapsible sidebar with grouped navigation items and a persistent header (sidebar toggle, theme toggle, user menu). There is no status bar. It is organized into customer-scoped sections (Roles, Users, Workspaces, Invitations, System) and workspace-scoped Configuration sections (Metadata, Terminology, Knowledge, Object Types, Templates, Lifecycle, Workflows, Settings, Staging Area, Work Packages). PDF stylesheet and variant management is workspace-scoped configuration and belongs in the Configuration group alongside Templates and Workflows.

The author-facing publish action and job monitoring live in the Platform App, triggered contextually from Objects/Recipes the author is already viewing.

Why the Admin Portal and not the Platform App Settings page?


2. Route Map (New Routes)

Admin Portal (separate application)

Routes follow the same pattern as all other Admin Portal workspace-scoped pages:

/c/:customerId/ws/:workspaceId/
├── pdf-publishing → PDF Publishing — Stylesheet list
├── pdf-publishing/:stylesheetId → Stylesheet detail (tabs: Config | Styling | History)
└── pdf-publishing/jobs → All workspace publish jobs (admin view)

Platform App (author-facing)

/ws/:workspaceId/
├── authoring → (existing — adds Publish action)
├── object-authoring → (existing — adds Publish button)
└── publish-jobs/ → My publish jobs (author view)
 └── :jobId → Job detail

3. Admin Screens (Admin Portal)

All admin screens below live in the Admin Portal — the separate workspace administration frontend. The Admin Portal shell has a collapsible sidebar with grouped navigation and a persistent header (sidebar toggle, theme toggle, user menu) with no status bar. PDF Publishing appears as a new item in the Configuration group of the sidebar (alongside Templates, Workflows, Settings, etc.), and is workspace-scoped: the active workspace is selected via the Workspace Switcher at the top of the sidebar and reflected in the URL (/c/:customerId/ws/:workspaceId/...).

3.1 PDF Publishing — Stylesheet List

Route: /c/:customerId/ws/:workspaceId/pdf-publishing

Access: Admin capability required (enforced by RouteAccessBoundary)

Entry point: Admin Portal sidebar → Configuration group → "PDF Publishing"

┌─────────────────────────────────────────────────────────────────────┐
│ [Page header: "PDF Publishing" [+ Create Stylesheet]] │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Name │ Template │ Variants │ Modified│ │
│ ├─────────────────────────────────────────────────────────────┤ │
│ │ Customer Manual │ Standard A4 │ 3 │ May 12 │ │
│ │ Service Guide │ Technical Compact │ 2 │ May 10 │ │
│ │ Training Material │ Standard A4 │ 1 │ Apr 28 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ [Empty state: illustration + "No stylesheets configured yet" │
│ + "Create your first stylesheet to enable PDF publishing" │
│ + CTA: "Create Stylesheet"] │
│ │
└─────────────────────────────────────────────────────────────────────┘

Interactions:


3.2 Create Stylesheet Dialog

Trigger: "+ Create Stylesheet" button

Type: Modal dialog (Table + Dialog CRUD pattern — A4.2)

┌───────────────────────────────────────────────────┐
│ Create Stylesheet [✕] │
├───────────────────────────────────────────────────┤
│ │
│ Name * │
│ ┌─────────────────────────────────────────────┐ │
│ │ e.g. "Customer Manual" │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ Description │
│ ┌─────────────────────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ Template * │
│ ┌─────────────────────────────────────────────┐ │
│ │ Select a PDF template... ▾ │ │
│ └─────────────────────────────────────────────┘ │
│ ↳ Shows available templates grouped: │
│ • Standard (platform-wide) │
│ • Workspace-specific │
│ │
│ [Cancel] [Create] │
└───────────────────────────────────────────────────┘

Validation:

On success: Dialog closes → list refreshes → new row highlighted


3.3 Stylesheet Detail

Route: /c/:customerId/ws/:workspaceId/pdf-publishing/:stylesheetId

Purpose: View/edit stylesheet configuration + manage variants

┌─────────────────────────────────────────────────────────────────────┐
│ [Page header: "Customer Manual" [Delete]] │
│ [Tabs: Configuration | Styling | History] │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ── Configuration Tab (default) ────────────────────────────────── │
│ │
│ ┌─ Stylesheet Properties ────────────────────────────────────┐ │
│ │ Name: [Customer Manual ] [Save] │ │
│ │ Template: Standard A4 (v2.1) [Change template...] │ │
│ │ Description: [Corporate customer documentation ] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ── Variants ────────────────────────────────────────────────── │
│ [+ Add Variant] │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Name │ Watermark │ Quality │ Actions │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ Review PDF │ DRAFT │ Screen │ [Edit] [⋯] │ │
│ │ Print PDF │ None │ High │ [Edit] [⋯] │ │
│ │ Confidential │ CONFIDENTIAL│ Screen │ [Edit] [⋯] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

Tab navigation:


3.4 Variant Editor

Trigger: "+ Add Variant" or "Edit" on existing variant

Type: Modal dialog (Table + Dialog CRUD pattern — A4.2)

┌────────────────────────────────────────────────────────┐
│ [Edit Variant: "Review PDF"] [✕] │
├────────────────────────────────────────────────────────┤
│ │
│ Name * │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Review PDF │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ Description │
│ ┌───────────────────────────────────────────────────┐ │
│ │ For internal review cycles. Draft watermark... │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ ── Output Parameters ──────────────────────────────── │
│ │
│ Watermark │
│ ┌───────────────────────────────────────────────────┐ │
│ │ DRAFT ▾ │ │
│ └───────────────────────────────────────────────────┘ │
│ Options: None | DRAFT | CONFIDENTIAL | APPROVED | │
│ Custom text... │
│ │
│ Draft Stamp [● On ○ Off] │
│ │
│ Output Quality │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Screen (optimised) ▾ │ │
│ └───────────────────────────────────────────────────┘ │
│ Options: Screen (optimised) | Print (high-res) │
│ │
│ Image Resolution │
│ ┌───────────────────────────────────────────────────┐ │
│ │ 150 DPI ▾ │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ Page Numbering Style │
│ ┌───────────────────────────────────────────────────┐ │
│ │ 1, 2, 3... ▾ │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ Include Review Annotations [○ On ● Off] │
│ │
│ │
│ [Cancel] [Save Variant] │
└────────────────────────────────────────────────────────┘

Delete variant: Accessed from the kebab menu (⋯) on the variant row. Triggers destructive confirmation dialog (Admin Portal confirmation pattern — A4.9).


3.5 No-Code Styling Editor

Route: /c/:customerId/ws/:workspaceId/pdf-publishing/:stylesheetId (Styling tab)

Tab: "Styling" tab on stylesheet detail

┌─────────────────────────────────────────────────────────────────────┐
│ [Tab: Styling] │
├───────────────────────────────────┬─────────────────────────────────┤
│ STYLING CONTROLS │ LIVE PREVIEW │
│ ───────────────────────── │ ───────────────────────── │
│ │ │
│ Font Family * │ ┌───────────────────────────┐ │
│ ┌─────────────────────────────┐ │ │ │ │
│ │ Inter ▾ │ │ │ [Rendered PDF preview │ │
│ └─────────────────────────────┘ │ │ showing selected fonts │ │
│ │ │ and colors applied to │ │
│ Body Font Size │ │ sample content] │ │
│ ┌──────────┐ │ │ │ │
│ │ 11pt │ ← stepper │ │ │ │
│ └──────────┘ │ │ │ │
│ │ │ │ │
│ Heading Font Size │ │ │ │
│ ┌──────────┐ │ │ │ │
│ │ 16pt │ ← stepper │ │ │ │
│ └──────────┘ │ │ │ │
│ │ │ │ │
│ ── Colors ────────────────────── │ │ │ │
│ │ │ │ │
│ Primary Color │ │ │ │
│ [■ #1E3A5F] ← color picker │ │ │ │
│ │ │ │ │
│ Heading Color │ │ │ │
│ [■ #2C5282] ← color picker │ │ │ │
│ │ │ │ │
│ Accent Color │ │ │ │
│ [■ #3182CE] ← color picker │ │ │ │
│ │ │ │ │
│ │ └───────────────────────────┘ │
│ │ │
│ [Reset to defaults] [Save] │ [Preview updates on change] │
│ │ │
└───────────────────────────────────┴─────────────────────────────────┘

Interactions:


3.6 Revision History

Route: /c/:customerId/ws/:workspaceId/pdf-publishing/:stylesheetId (History tab)

Tab: "History" tab on stylesheet detail

┌─────────────────────────────────────────────────────────────────────┐
│ [Tab: History] │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Rev │ Date │ User │ Change │ Act │ │
│ ├───────────────────────────────────────────────────────────────┤ │
│ │ 5 │ May 12, 14:32 │ Anna S. │ Styling │ ● │ │
│ │ 4 │ May 10, 09:15 │ Anna S. │ Template │ ⟲ │ │
│ │ 3 │ Apr 28, 16:44 │ Erik M. │ Restored │ ⟲ │ │
│ │ 2 │ Apr 20, 11:02 │ Erik M. │ Styling │ ⟲ │ │
│ │ 1 │ Mar 15, 08:30 │ Anna S. │ Created │ ⟲ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
│ ● = current revision │
│ ⟲ = restore action │
│ │
│ [Click row to inspect revision details in side panel] │
│ │
└─────────────────────────────────────────────────────────────────────┘

Interactions:


3.7 Admin Job Overview

Route: /c/:customerId/ws/:workspaceId/pdf-publishing/jobs

Purpose: Administrators see all workspace publish jobs (all users) in the Admin Portal

┌─────────────────────────────────────────────────────────────────────┐
│ [Page header: "Publish Jobs" + filter controls] │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ Filters: [Status ▾] [Initiator ▾] [Date range] [Search...] │
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Object/Recipe │ Variant │ User │ Status │ Date │ │
│ ├────────────────────────────────────────────────────────────────┤ │
│ │ Safety Manual │ Print PDF │ Erik │ ✓ Done │ 14:32 │ │
│ │ Install Guide │ Review PDF │ Anna │ ◐ Proc │ 14:30 │ │
│ │ Maintenance Op │ Print PDF │ Erik │ ✗ Fail │ 14:25 │ │
│ │ Quick Start │ Review PDF │ Per │ ◷ Queue │ 14:22 │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

4. Author Screens (Platform App)

All author screens below live in the Platform App — the primary user-facing application.

4.1 Publish Action Entry Points

Publishing is triggered contextually from places the author already is. Three entry points:

| Entry Point | Location | Scope |
|---|---|---|
| **Object List action** | Author View → Object List → context menu or action bar | Single object |
| **Object Authoring toolbar** | Object Authoring page → action bar | Single object (currently open) |
| **Recipe view action** | Recipe object detail → action bar (Phase 2) | Full recipe |

All entry points open the same Publish Dialog (§4.2).

Object List (modified):

┌────────────────────────────────────────────────────────────────────┐
│ [Action bar: + Create | ↓ Import | ⎙ Publish PDF | ...] │
├────────────────────────────────────────────────────────────────────┤
│ ☐ Name │ Type │ Status │ Modified │ Author│
│ ──────────────────────────────────────────────────────────────── │
│ ☑ install-procedure.xml │ DITA │ Checked In │ May 12 │ Anna │
│ ☐ safety-warning.xml │ DITA │ Checked In │ May 10 │ Erik │
└────────────────────────────────────────────────────────────────────┘
 ↑
 "Publish PDF" enabled when 1 XML object selected

Object Authoring toolbar (modified):

┌────────────────────────────────────────────────────────────────────┐
│ install-procedure.xml │
│ [Save] [Check In] [Check Out] | [⎙ Publish PDF] | [Close] │
└────────────────────────────────────────────────────────────────────┘

4.2 Publish Dialog

Trigger: "Publish PDF" action (any entry point)

Type: Modal dialog (Radix UI Dialog)

Purpose: Select language, select variant, and confirm publish

┌───────────────────────────────────────────────────────────────┐
│ Publish as PDF [✕] │
├───────────────────────────────────────────────────────────────┤
│ │
│ Publishing: install-procedure.xml │
│ Version: 2.1 / Subversion 3 │
│ │
│ ── Language ─────────────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ English (EN) — source ★ ▾ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ Options: English (EN) ★ | Deutsch (DE) | Français (FR) │
│ │
│ ── Select Output Variant ────────────────────────────────── │
│ │
│ Customer Manual │
│ ○ Review PDF — Draft watermark, screen quality │
│ ● Print PDF — No watermark, high resolution │
│ ○ Confidential — Confidential watermark │
│ │
│ Service Guide │
│ ○ Technical Review — Annotations enabled │
│ ○ Final Print — Print-ready quality │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ℹ PDF will be generated from the selected language. │ │
│ │ Only languages with an approved LanguageVariant are │ │
│ │ listed. Source language is selected by default. │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ [Cancel] [⎙ Publish] │
└───────────────────────────────────────────────────────────────┘

Interactions:

Validation error states:

┌───────────────────────────────────────────────────────────────┐
│ Publish as PDF [✕] │
├───────────────────────────────────────────────────────────────┤
│ │
│ ⚠ Cannot publish this object │
│ │
│ • Source XML is malformed (line 42: unclosed element) │
│ │
│ [Fix the issue and try again] │
│ │
│ [Close] │
└───────────────────────────────────────────────────────────────┘

4.3 Recipe Publish Dialog (Phase 2)

Trigger: "Publish PDF" on a Recipe object

Type: Modal dialog (Radix UI Dialog) — extended variant of §4.2

┌───────────────────────────────────────────────────────────────┐
│ Publish Recipe as PDF [✕] │
├───────────────────────────────────────────────────────────────┤
│ │
│ Recipe: Safety Manual - Hydraulic Systems │
│ Objects: 24 resolved sections │
│ │
│ ── Language ─────────────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ English (EN) — source ★ ▾ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ Options (dropdown): │
│ English (EN) ★ — all 24 objects │
│ Deutsch (DE) — all 24 objects │
│ Français (FR) — ⚠ 18 of 24 objects (6 missing) │
│ 日本語 (JA) — ⚠ 5 of 24 objects (19 missing) │
│ │
│ ── Select Output Variant ────────────────────────────────── │
│ │
│ Customer Manual │
│ ○ Review PDF │
│ ● Print PDF │
│ │
│ ── Profile Filter (optional) ────────────────────────────── │
│ │
│ Narrow output with a temporary filter: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ None (use saved Recipe filter) ▾ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ Options: None | Market: Europe | Market: North America | ... │
│ │
│ ── Validation ───────────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ⚠ 2 warnings │ │
│ │ • Node "Appendix C" resolves to no content (omitted) │ │
│ │ • Node "Legacy parts" contains only image assets │ │
│ │ │ │
│ │ ☑ I acknowledge these warnings and wish to proceed │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ℹ A publish-time snapshot will be frozen. The PDF │ │
│ │ reflects content at this moment. │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ [Cancel] [⎙ Publish] │
└───────────────────────────────────────────────────────────────┘

Recipe publish — language dropdown note:

For Recipe publish, the language dropdown lists all languages that appear in at least one resolved object:

When a partial language is selected, a contextual inline warning appears immediately below the language dropdown (above the variant selector). The Publish button remains disabled until the user checks the acknowledgement checkbox:

┌─────────────────────────────────────────────────────────────┐
│ ⚠ 6 objects have no Français (FR) translation. │
│ These will fall back to source language (EN) │
│ in the generated PDF. │
│ │
│ ▽ Show affected objects │
│ • appendix-c.xml │
│ • safety-notes.xml │
│ • ...4 more │
│ │
│ ☐ I understand some sections will be in English (EN) │
└─────────────────────────────────────────────────────────────┘

The affected-objects list is collapsed by default and expands on click.

Single-object publish — language dropdown note:

For single-object publish, the dropdown lists all LanguageVariants present on the current Subversion. Source language is pre-selected by default.

Interactions:

│ ── Validation ───────────────────────────────────────────── │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ✗ Cannot publish — resolve these issues first: │ │
│ │ │ │
│ │ • Node "Chapter 4" resolves to 3 objects │ │
│ │ (ambiguous — must resolve to exactly 1) │ │
│ │ • Node "Appendix A" resolves to 2 objects │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ [Cancel] [Publish] (disabled) │

4.4 Publish Jobs — Author View

Route: /ws/:workspaceId/publish-jobs

Access: Author capability

Entry points:

┌─────────────────────────────────────────────────────────────────────┐
│ [Page header: "My PDF Jobs"] │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ Object/Recipe │ Variant │ Status │ Date │ │
│ ├────────────────────────────────────────────────────────────────┤ │
│ │ install-proc.xml │ Print PDF │ ✓ Completed │ 14:32 │ │
│ │ │ │ [↓ Download] │ │ │
│ │────────────────────────────────────────────────────────────────│ │
│ │ safety-manual │ Review PDF │ ◐ Rendering │ 14:30 │ │
│ │ (Recipe, 24 obj) │ │ Stage 3 of 5 │ │ │
│ │────────────────────────────────────────────────────────────────│ │
│ │ quick-start.xml │ Print PDF │ ✗ Failed │ 14:25 │ │
│ │ │ │ [View error] │ │ │
│ │────────────────────────────────────────────────────────────────│ │
│ │ maintenance.xml │ Review PDF │ ◷ Queued (#3) │ 14:22 │ │
│ └────────────────────────────────────────────────────────────────┘ │
│ │
│ [Empty state: "No publish jobs yet" │
│ "Publish your first PDF from the Authoring view"] │
│ │
└─────────────────────────────────────────────────────────────────────┘

Row interactions:

Alternative placement — Panel in Author View:

┌──────────────┬────────────────────────┬────────────────────────────┐
│ ZONE A │ ZONE B │ ZONE C │
│ Folder │ Object List │ Preview │
│ Explorer │ │ │
│ ├────────────────────────┤ │
│ │ Properties │ Versions │
│ ├────────────────────────┤────────────────────────────│
│ │ Publish Jobs ← NEW │ │
│ │ (recent jobs for │ │
│ │ selected object) │ │
└──────────────┴────────────────────────┴────────────────────────────┘

This panel variant shows jobs scoped to the currently selected object/recipe. The full jobs page shows all workspace jobs.


4.5 Job Detail

Trigger: Click a job row in the job list

Type: Side sheet (Radix UI Sheet) or navigate to /publish-jobs/:jobId

┌────────────────────────────────────────────────────────────────┐
│ PDF Publish Job [✕] │
├────────────────────────────────────────────────────────────────┤
│ │
│ Source: install-procedure.xml │
│ Type: Single Object │
│ Variant: Customer Manual > Print PDF │
│ Language: EN │
│ Initiated: May 12, 14:30 by Anna S. │
│ │
│ ── Progress ───────────────────────────────────────────────── │
│ │
│ ✓ Queued 14:30:01 │
│ ✓ Validating 14:30:02 │
│ ✓ Packaging 14:30:03 │
│ ● Rendering 14:30:05 ← in progress │
│ ○ Storing │
│ ○ Completed │
│ │
│ ── Details ────────────────────────────────────────────────── │
│ │
│ Stylesheet: Customer Manual (rev 5) │
│ Template: Standard A4 (v2.1) │
│ Job ID: 01jq8f... │
│ │
│ [When completed:] │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ✓ PDF ready │ │
│ │ Size: 2.4 MB | Pages: 12 │ │
│ │ Expires: Jun 12, 2026 │ │
│ │ │ │
│ │ [↓ Download PDF] │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ [When failed:] │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ✗ Generation failed │ │
│ │ Error: Font "CustomSans" not found in font catalogue │ │
│ │ Fallback was attempted but failed for 3 glyphs. │ │
│ │ │ │
│ │ Attempts: 2 of 3 │ │
│ │ [⟲ Retry] [Dismiss] │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────┘

Recipe job detail adds:

│ ── Recipe Sections (24 included) ─────────────────────────── │
│ │
│ 1. Introduction safety-intro.xml ✓ │
│ 2. Hydraulic System hydraulic-overview.xml ✓ │
│ 3. Maintenance maintenance-proc.xml ● current │
│ 4. Safety Precautions safety-warn.xml ○ │
│ ... │
│ │
│ ── Warnings Acknowledged ─────────────────────────────────── │
│ • Node "Appendix C" omitted (no matching content) │
│ • Node "Legacy parts" omitted (non-renderable assets only) │

4.6 Real-Time Notifications

PDF job completion/failure triggers real-time notifications via SignalR:

Toast notification (in-app):

┌────────────────────────────────────────────────┐
│ ✓ PDF Ready: install-procedure.xml │
│ Print PDF • 2.4 MB │
│ [Download] [View Job] [Dismiss] │
└────────────────────────────────────────────────┘

Failed:

┌────────────────────────────────────────────────┐
│ ✗ PDF Failed: quick-start.xml │
│ Font substitution error │
│ [View Details] [Dismiss] │
└────────────────────────────────────────────────┘

Status bar (persistent, subtle):

┌─────────────────────────────────────────────────────────────────┐
│ [status bar] ◐ 2 PDF jobs processing | ✓ 1 PDF ready │
└─────────────────────────────────────────────────────────────────┘

Clicking the status bar indicator navigates to /publish-jobs.


4.7 Expired PDF State

When a user tries to download an expired PDF:

┌────────────────────────────────────────────────────────────────┐
│ PDF Publish Job [✕] │
├────────────────────────────────────────────────────────────────┤
│ │
│ Source: install-procedure.xml │
│ Status: Expired │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ⚠ PDF no longer available │ │
│ │ This file expired on Jun 12, 2026 per workspace │ │
│ │ retention policy. │ │
│ │ │ │
│ │ [⎙ Re-publish with same settings] │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────┘

5. No Stylesheets Configured (Author-Facing)

When an author tries to publish but no stylesheets/variants exist:

┌───────────────────────────────────────────────────────────────┐
│ Publish as PDF [✕] │
├───────────────────────────────────────────────────────────────┤
│ │
│ [Illustration: empty clipboard] │
│ │
│ No publishing options available │
│ │
│ Your workspace doesn't have any PDF stylesheets │
│ configured yet. Ask your workspace administrator to │
│ set up PDF publishing in the Admin Portal. │
│ │
│ [Close] │
└───────────────────────────────────────────────────────────────┘

6. User Flows

Flow A: Administrator Sets Up PDF Publishing (First Time)

Admin opens the Admin Portal
 → selects workspace in the Workspace Switcher
 → navigates to Configuration → "PDF Publishing"
 → /c/{customerId}/ws/{wsId}/pdf-publishing loads (empty state)
 → clicks "+ Create Stylesheet"
 → Create Stylesheet dialog opens
 → fills name: "Customer Manual"
 → selects template: "Standard A4"
 → clicks Create
 → dialog closes, stylesheet appears in list
 → clicks stylesheet row → detail page
 → clicks "+ Add Variant"
 → Variant dialog opens
 → fills name: "Review PDF"
 → sets watermark: DRAFT
 → sets quality: Screen
 → clicks Save Variant
 → variant appears in list
 → repeats for "Print PDF" variant
 → done: authors can now publish

Flow B: Author Publishes Single Object (3 Clicks)

Author is in /authoring, viewing Object List
 → selects XML object (click 1)
 → action bar shows "Publish PDF" button
 → clicks "Publish PDF" (click 2)
 → Publish Dialog opens
 → language dropdown pre-selects source language (EN)
 → variants are pre-loaded, grouped by stylesheet
 → selects "Print PDF" radio (click 3)
 → clicks "Publish" button
 → dialog closes
 → toast: "PDF job queued"
 → [seconds later] toast: "✓ PDF ready — Download"
 → clicks Download → PDF saves to local machine

Flow C: Author Publishes from Object Authoring

Author is editing an object in /object-authoring
 → clicks "Publish PDF" in toolbar
 → Publish Dialog opens (same as Flow B)
 → selects variant → publishes
 → continues editing while PDF generates in background
 → toast notification when ready

Flow D: Author Publishes Recipe (Phase 2)

Author views Recipe in Author View
 → selects Recipe object → clicks "Publish PDF"
 → Recipe Publish Dialog opens
 → shows "24 resolved sections"
 → language dropdown pre-selects source language (EN)
 → available options = intersection of languages across all resolved objects
 → pre-validation runs automatically:
 → 2 warnings shown (omitted nodes)
 → no blocking errors
 → author checks "I acknowledge warnings"
 → selects variant: "Print PDF"
 → optionally selects narrowing filter: "Market: Europe"
 → clicks "Publish"
 → dialog closes, toast: "Recipe PDF job queued"
 → [longer processing for multi-object assembly]
 → status bar: "◐ 1 Recipe PDF processing"
 → toast: "✓ Recipe PDF ready (48 pages)"

Flow E: Author Monitors Active Jobs

Author has multiple PDFs in flight
 → status bar shows: "◐ 2 PDF jobs processing"
 → clicks status bar indicator
 → navigates to /publish-jobs
 → sees list of all their jobs
 → one completes → row updates in real time (SignalR)
 → "Download" button appears
 → one fails → row shows error state
 → clicks "View error" → Job Detail side sheet opens
 → reads error description
 → clicks "Retry" → job re-queued

Flow F: Administrator Restores Stylesheet Revision

Admin is in Admin Portal, on stylesheet detail
 → clicks "History" tab
 → sees chronological list of revisions
 → clicks revision #2 row
 → side sheet opens with read-only view of rev 2 config
 → clicks "Restore this revision"
 → confirmation dialog: "Restore to revision 2?"
 → confirms
 → new revision #6 created (records restore action)
 → "Configuration" tab shows restored values
 → toast: "Stylesheet restored to revision 2"

Flow G: Admin Adjusts Branding (No-Code Styling)

Admin is in Admin Portal, opens stylesheet detail
 → clicks "Styling" tab
 → sees left panel with font/color controls
 → sees right panel with live preview
 → changes font family to "Helvetica"
 → preview updates immediately
 → changes heading color to corporate blue
 → preview updates immediately
 → clicks "Save"
 → new revision created
 → toast: "Styling updated"

7. State Machine — Publish Job Lifecycle

 ┌─────────┐
 Publish ────────│ Queued │
 request └────┬────┘
 │
 ┌────▼────┐
 │Validating│
 └────┬────┘
 │
 ┌──────────┼──────────┐
 │ (pass) │ │ (fail)
 ┌────▼────┐ │ ┌────▼────┐
 │Packaging│ │ │ Failed │◄── retry limit reached
 └────┬────┘ │ └─────────┘
 │ │ ▲
 ┌────▼────┐ │ │ (render error + retries left)
 │Rendering│─────┘──────────┘
 └────┬────┘
 │ (success)
 ┌────▼────┐
 │ Storing │
 └────┬────┘
 │
 ┌────▼─────┐ ┌─────────┐
 │Completed │────────▶│ Expired │ (retention period elapsed)
 └──────────┘ └─────────┘

8. Capability Gating

| Capability | Protects |
|---|---|
| `CapabilityAdmin` | Stylesheet CRUD, variant CRUD, styling editor, revision history, restore, admin job view (Admin Portal) |
| Author (or higher) | Publish action, job list, download completed PDFs (Platform App) |
| Feature flag: `pdfPublishing` | Entire feature visibility (Admin Portal section + Platform App publish actions) |

When the feature flag is disabled, the Admin Portal section and all publish buttons in the Platform App are hidden.


9. Loading & Skeleton States

Stylesheet List Skeleton

┌──────────────────────────────────────────────────────┐
│ ████████████████ ████████ ██ █████████ │
│ ██████████████████████ ████████ ██ █████████ │
│ ████████████████ ████████ ██ █████████ │
└──────────────────────────────────────────────────────┘

Publish Dialog Skeleton

┌─────────────────────────────────────────────┐
│ Publish as PDF │
│ ─────────────── │
│ ████████████████████████ │
│ ████████████ │
│ │
│ ██████████████████████████████████████ │
│ ○ █████████████████ │
│ ○ ██████████████ │
│ ○ ████████████████████ │
│ │
│ [Cancel] [Publish] (dim) │
└─────────────────────────────────────────────┘

Job Detail Skeleton

┌─────────────────────────────────────────────┐
│ ████████ █████████████████████ │
│ ████████ ██████████ │
│ ████████ ███████████████ │
│ │
│ ○───●───○───○───○───○ stage indicator │
│ │
│ ████████████████████████████████ │
└─────────────────────────────────────────────┘

10. Error States

Publish Action — Object Not Publishable

Non-XML objects (images, binaries) do not show the "Publish PDF" action at all. The button is hidden from the UI rather than shown disabled, to reduce noise.

Job Permanently Failed (Max Retries Exhausted)

┌─────────────────────────────────────────────────────────┐
│ ✗ Permanently Failed │
│ │
│ This job has failed after 3 attempts. │
│ Error: Renderer timeout after 300s │
│ │
│ The content may be too complex for the current │
│ renderer configuration. Contact your administrator. │
│ │
│ [Re-publish as new job] [Dismiss] │
└─────────────────────────────────────────────────────────┘

Network Error During Publish Request

Standard platform error toast. The dialog stays open so the user can retry without re-selecting their variant.


11. Responsive Behavior

| Breakpoint | Behavior |
|---|---|
| Desktop (≥ 768px) | Full layout — side-by-side preview in styling editor, side sheets for detail |
| Mobile (< 768px) | Styling editor stacks vertically (controls above preview). Publish dialog goes full-screen sheet. Job list single-column. |

Admin stylesheet management is desktop-primary (complex configuration). Publish action and job monitoring must work on mobile.


12. Accessibility Considerations


13. Integration with Existing Patterns

| Pattern | How PDF Publishing uses it |
|---|---|
| Page Header | Settings subpage + author job list |
| Empty State | Stylesheet list, job list, publish dialog (no variants) |
| Error State | Job failures, publish validation errors |
| Loading Skeleton | Every panel/page has dedicated skeleton |
| Dialog | Create stylesheet, publish confirmation |
| Confirmation dialog (A4.9) | Delete confirmation (stylesheet, variant) |
| Sheet (side) | Variant editor, job detail, revision inspector |
| Context Menu | Stylesheet row actions (rename, delete) |
| Status Bar | Active job count indicator |
| Toast | Job queued, completed, failed notifications |
| Real-time (SignalR) | Job completion/failure push |

14. URL State Conventions

Admin Portal

| State | Mechanism | Example |
|---|---|---|
| Active workspace | URL path segment | `/c/:customerId/ws/:workspaceId/...` |
| Selected stylesheet | URL path segment | `/c/:customerId/ws/:workspaceId/pdf-publishing/:stylesheetId` |
| Active tab | URL search param | `?tab=styling` |
| Admin job filter/sort | URL search params | `?status=failed&sort=date` |

Platform App

| State | Mechanism | Example |
|---|---|---|
| Job detail | URL path or sheet param | `/ws/:wsId/publish-jobs/:jobId` |
| Publish dialog open | Transient UI state (no URL) | — |
| Filter/sort on job list | URL search params | `?status=failed&sort=date` |

15. Admin Tool Navigation Integration

The Admin Tool sidebar gains a new section alongside existing admin features:

┌──────────────────────────────────────────────────────┐
│ [Admin Tool sidebar] │
├──────────────────────────────────────────────────────┤
│ │
│ ⊞ Dashboard │
│ &#128101; Roles & Capabilities │
│ ⚙ Workflows │
│ &#128268; External Tools │
│ &#128203; Templates │
│ &#128196; PDF Publishing ← NEW │
│ &#128230; Metadata Domains │
│ ... │
│ │
└──────────────────────────────────────────────────────┘

Clicking "PDF Publishing" navigates to /admin/workspaces/:workspaceId/pdf-publishing.

> Note: The Platform App Settings page is unchanged. It remains focused on personal user preferences (theme, language, notifications) and does not gain any PDF publishing configuration.


16. Design Decisions & Rationale

| Decision | Rationale |
|---|---|
| Publish is an action, not a page | Authors shouldn't leave their workflow context to publish — it's a 3-click inline action |
| Variants grouped by stylesheet in dialog | Reduces cognitive load by showing the organizational hierarchy rather than a flat list |
| Side sheet for variant editor | Variant configuration is moderately complex but doesn't warrant a full page navigation |
| Tabs on stylesheet detail | Separates concerns (config vs. styling vs. history) without page navigation |
| Real-time status updates | Publishing is async — users need immediate feedback without polling/refreshing |
| Stage-based progress (not percentage) | Stages communicate meaningful state; percentage implies false precision for async rendering |
| Job list as dedicated page + optional panel | Dedicated page for full job management; optional panel in Author View for quick context |
| Hide (not disable) publish on non-XML | Reduces UI noise; non-publishable objects don't need to explain why they can't publish |
| Feature flag hides entire surface | Clean capability boundary — either the workspace has PDF publishing or it doesn't (hidden in both Admin Tool and Platform App) |