Specification
Author: Claude Code for jmpicnic Date: 2026-03-30 Status: Draft
Summary
Section titled “Summary”Extend the printing format system with X_SMALL and SPECIAL_01 through SPECIAL_10 enum values for all three print types (card, label, breadcrumb). Update the Documint template spreadsheet, backend configuration and code in operations, and deliver a frontend specification as a GitHub ticket for arda-frontend-app.
Context
Section titled “Context”- Goal file: Extra Printing Options — Goal
- Worktrees:
extra-printing-options-worktrees/{operations,documentation}on branchjmpicnic/extra-printing-options-management-820 - Spreadsheet: Printing Template Mapping (readable/writable via Google Workspace MCP)
- Project type: Modification — extending existing enums, protobuf definitions, configuration, and CSV upload logic.
In Scope
Section titled “In Scope”- Spreadsheet — New versioned sheet with
X_SMALL,SPECIAL_01–10rows,Activecolumn, andNotescolumn. - Backend (
operations) — Domain enums, protobuf enums, protobuf-to-domain mapping,PrintingTemplateConfigurationdata class,pdf-templates.json, CSV alias support. - Frontend ticket — Detailed GitHub issue in
Arda-cards/managementassigned todanmerbspecifying frontend changes forarda-frontend-app.
Out of Scope
Section titled “Out of Scope”- Direct modifications to
arda-frontend-app(delivered as a ticket only). - Changes to
common-module(reference dependency only). - Changes to breadcrumb/label/card rendering logic or Documint template design.
- New API endpoints — existing print endpoints are unchanged.
General Instructions
Section titled “General Instructions”- Follow the
implementation-taskskill for execution workflow and expected byproducts. - Follow guidelines in
dev-workflows.mdfor build and test commands. - Use
git -C <path>instead ofcd <path> && gitfor cross-repo git operations.
Task Breakdown
Section titled “Task Breakdown”| # | Task | Phase | Depends On | Acceptance Criteria |
|---|---|---|---|---|
| T-1 | Create new spreadsheet sheet with all rows and columns | 1: Spreadsheet | — | New sheet exists with 45 data rows (15 per category), Active and Notes columns populated |
| T-2 | Extend domain enums in Printing.kt | 2: Backend | T-1 | CardSize, LabelSize, BreadcrumbSize each have X_SMALL, SMALL, MEDIUM, LARGE, X_LARGE, SPECIAL_01–SPECIAL_10 |
| T-3 | Extend protobuf enums in item_row.proto | 2: Backend | T-1 | Sequential field numbers, all new values present |
| T-4 | Update protobuf → domain mapping in ItemCsvUploadService.kt | 2: Backend | T-2, T-3 | All new protobuf values map to correct domain values; UNSPECIFIED still defaults to MEDIUM |
| T-5 | Add CSV aliases for Size of Template display names | 2: Backend | T-4 | CSV upload accepts display names (e.g., “Quarter-Index”) as aliases for enum values |
| T-6 | Add active field to PrintingTemplateConfiguration | 2: Backend | — | Data class includes active: Boolean, defaults to true for backwards compatibility |
| T-7 | Update pdf-templates.json with all entries from spreadsheet | 2: Backend | T-1, T-6 | All 45 entries present with correct template IDs, columns, descriptions, and active flags |
| T-8 | Verify existing data deserialization | 2: Backend | T-2, T-7 | Items with SMALL/MEDIUM/LARGE/X_LARGE deserialize and print correctly |
| T-9 | Update existing tests, add tests for new values | 2: Backend | T-2–T-7 | All tests pass including new enum values and CSV aliases |
| T-10 | make clean build and verify coverage | 2: Backend | T-2–T-9 | Zero errors, zero test failures, code coverage meets or exceeds Gradle-configured targets |
| T-11 | Update CHANGELOG.md | 2: Backend | T-10 | Entry added under new version with Added section |
| T-12 | Write frontend specification and create GitHub ticket | 3: Frontend Ticket | T-1, T-10 | Ticket created in Arda-cards/management, assigned to danmerb, with full acceptance criteria including npm coverage targets |
Phase Details
Section titled “Phase Details”Phase 1: Spreadsheet Update (T-1)
Section titled “Phase 1: Spreadsheet Update (T-1)”Create a new sheet called Documint Template Mapping (YYYYMMDD) (where YYYYMMDD is today’s date) by populating it with the following structure.
Columns: Form, Size (Back-end names), Number of columns, Documint Template, Default, Size of Template (UI Displayed name), Template Change, Name Change, Template URL, Active, Notes
Rows per category (Label, Breadcrumb, Kanban Card): copy existing X_SMALL through X_LARGE rows from the (20260129) sheet, then add SPECIAL_01 through SPECIAL_10.
Specific transformations:
- For Kanban Card / SPECIAL_01: copy values from the
LARGE+QRrow (template690a35cc4d1069adadcc052c, 1 column, “3 x 5 - Large QR Code”). SetActive = TRUE. - For all other
SPECIAL_NNrows: copy the template ID, columns, and description from theDefaultrow of that category (the row marked withXin the Default column). SetActive = FALSE. - For Breadcrumb / X_SMALL: change the display name to “3 x 1 (xs Label Printer)” (strip the “Dup-” prefix and differentiate from SMALL). Add a
Notesentry: “Shares template ID with Breadcrumb/SMALL (695eb8be226280f110894177)”. - Set
Active = TRUEfor all rows fromX_SMALLthroughX_LARGE(all categories) andSPECIAL_01(Kanban Card only). - Set
Active = FALSEfor all otherSPECIAL_NNrows. - The
LARGE+QRrow is not carried forward to the new sheet (its values are inSPECIAL_01).
STOP — Review checkpoint after Phase 1
Section titled “STOP — Review checkpoint after Phase 1”Verify the new sheet has the correct row count and structure before proceeding to backend changes.
Phase 2: Backend Implementation (T-2 through T-11)
Section titled “Phase 2: Backend Implementation (T-2 through T-11)”Worktree: extra-printing-options-worktrees/operations
T-2: Extend domain enums
Section titled “T-2: Extend domain enums”In src/main/kotlin/cards/arda/operations/reference/item/domain/Printing.kt, add to each enum:
@Serializableenum class CardSize { X_SMALL, SMALL, MEDIUM, LARGE, X_LARGE, SPECIAL_01, SPECIAL_02, SPECIAL_03, SPECIAL_04, SPECIAL_05, SPECIAL_06, SPECIAL_07, SPECIAL_08, SPECIAL_09, SPECIAL_10}Same pattern for LabelSize and BreadcrumbSize. Ordering: X_SMALL before SMALL (ascending logical size), then SPECIAL_* after X_LARGE.
T-3: Extend protobuf enums
Section titled “T-3: Extend protobuf enums”In src/main/proto/cards/arda/v1/operations/reference/item/csv/v1beta1/item_row.proto, extend each enum with sequential field numbers:
enum CardSize { CARD_SIZE_UNSPECIFIED = 0; CARD_SIZE_SMALL = 1; CARD_SIZE_MEDIUM = 2; CARD_SIZE_LARGE = 3; CARD_SIZE_EXTRA_LARGE = 4; CARD_SIZE_EXTRA_SMALL = 5; CARD_SIZE_SPECIAL_01 = 6; CARD_SIZE_SPECIAL_02 = 7; CARD_SIZE_SPECIAL_03 = 8; CARD_SIZE_SPECIAL_04 = 9; CARD_SIZE_SPECIAL_05 = 10; CARD_SIZE_SPECIAL_06 = 11; CARD_SIZE_SPECIAL_07 = 12; CARD_SIZE_SPECIAL_08 = 13; CARD_SIZE_SPECIAL_09 = 14; CARD_SIZE_SPECIAL_10 = 15;}Same pattern for LabelSize (prefix LABEL_SIZE_) and BreadcrumbSize (prefix BREADCRUMB_SIZE_). Note: new values are appended after existing values to maintain wire compatibility.
T-4: Update protobuf → domain mapping
Section titled “T-4: Update protobuf → domain mapping”In ItemCsvUploadService.kt, extend each mapping function. Example for CardSize:
fun CardSizeMessage.domain(): Result<CardSize> = when (this) { CardSizeMessage.CARD_SIZE_UNSPECIFIED -> Result.success(CardSize.MEDIUM) CardSizeMessage.CARD_SIZE_SMALL -> Result.success(CardSize.SMALL) CardSizeMessage.CARD_SIZE_MEDIUM -> Result.success(CardSize.MEDIUM) CardSizeMessage.CARD_SIZE_LARGE -> Result.success(CardSize.LARGE) CardSizeMessage.CARD_SIZE_EXTRA_LARGE -> Result.success(CardSize.X_LARGE) CardSizeMessage.CARD_SIZE_EXTRA_SMALL -> Result.success(CardSize.X_SMALL) CardSizeMessage.CARD_SIZE_SPECIAL_01 -> Result.success(CardSize.SPECIAL_01) // ... SPECIAL_02 through SPECIAL_10 CardSizeMessage.UNRECOGNIZED -> Result.failure(AppError.ArgumentValidation("cardSize", "unrecognized"))}T-5: Add CSV aliases
Section titled “T-5: Add CSV aliases”Add alias resolution so that CSV uploads can use the Size of Template display names as values. The alias map is derived from the spreadsheet:
Label aliases:
| Display Name | Enum Value |
|---|---|
| 3x1 (Label Printer) | X_SMALL |
| Quarter-Index | SMALL |
| Half-Index | MEDIUM |
| 3x2 (Label Printer) | LARGE |
| Business Card Stock | X_LARGE |
Breadcrumb aliases:
| Display Name | Enum Value |
|---|---|
| 3 x 1 (xs Label Printer) | X_SMALL |
| 3 x 1 (Label Printer) | SMALL |
| 3 x 2 (Label Printer) | MEDIUM |
| Business Card Stock | LARGE |
| Half-Index | X_LARGE |
Card aliases:
| Display Name | Enum Value |
|---|---|
| Quarter-Index | X_SMALL |
| Half-Index | SMALL |
| Business Card Stock | MEDIUM |
| 3 x 5 | LARGE |
| 3 x 5 - Large QR Code | SPECIAL_01 |
| 4 x 6 | X_LARGE |
T-6: Add active field to PrintingTemplateConfiguration
Section titled “T-6: Add active field to PrintingTemplateConfiguration”In src/main/kotlin/cards/arda/operations/shopaccess/pdfrender/business/RenderJob.kt, update the data class:
@Serializabledata class PrintingTemplateConfiguration( val template: String, val columns: Int, val description: String, val active: Boolean = true)The default = true ensures backwards compatibility — the existing default field in pdf-templates.json is already ignored by the deserializer (ignoreUnknownKeys), and active defaults to true if absent. The active flag is stored for future use but does not affect PrintTemplates resolution logic.
T-7: Update pdf-templates.json
Section titled “T-7: Update pdf-templates.json”Replace src/main/resources/reference/item/printing/pdf-templates.json with all 45 entries (15 per category) sourced from the new spreadsheet sheet. Each entry includes template, columns, description, default, and active.
For SPECIAL_NN rows where Active = FALSE, the template ID, columns, and description are copied from the category’s default row (the entry marked default: true).
T-8–T-10: Verification
Section titled “T-8–T-10: Verification”- Verify
enumerationByNamedeserialization: existing database rows withSMALL/MEDIUM/LARGE/X_LARGEmust load without error. - Run existing test suites; update test fixtures that enumerate size values.
make clean buildmust pass with zero errors.- Code coverage must meet or exceed the targets configured in the Gradle build scripts.
T-11: CHANGELOG
Section titled “T-11: CHANGELOG”Add entry under a new version (minor bump — new enum values are additive):
## [2.20.0-jmpicnic-820] - 2026-03-30
### Added- `X_SMALL` and `SPECIAL_01` through `SPECIAL_10` to `CardSize`, `LabelSize`, and `BreadcrumbSize` enums.- Protobuf enum values for all new sizes.- CSV upload alias support for `Size of Template` display names.- `active` flag in `PrintingTemplateConfiguration` for future frontend filtering.- 33 new entries in `pdf-templates.json`.STOP — Review checkpoint after Phase 2
Section titled “STOP — Review checkpoint after Phase 2”All backend changes must compile and pass tests before proceeding to the frontend ticket.
Phase 3: Frontend Ticket (T-12)
Section titled “Phase 3: Frontend Ticket (T-12)”Worktree: extra-printing-options-worktrees/documentation (for the specification text)
Create a GitHub issue in Arda-cards/management assigned to danmerb (using the /gh-ticket skill) containing:
- Context: Link to this specification and the parent issue #820.
- Changes required:
- Extend
cardSizeOptions,labelSizeOptions,breadcrumbSizeOptionsinconstants.tswith all new values. ReconcileX-SMALL(hyphenated) toX_SMALL(underscore). - Add an
enabledproperty to each option sourced from the spreadsheetActivecolumn. - Update TypeScript union types in
items.tsto include new values. - Update size mappers in
ardaMappers.ts. - Encapsulate size selection in a reusable React component per UX Component Guidelines.
- Only
enabledoptions are selectable in dropdowns; disabled options are visible but not selectable. - The array of size options should be determined at design time; the specific mappings of each option should be determined at mount time.
- Extend
- Acceptance criteria: Frontend-specific items from the goal file (criteria 15–20), including code coverage meeting or exceeding npm-configured targets.
Exclusions
Section titled “Exclusions”- Do not modify files in
arda-frontend-app. - Do not modify files in
common-module. - Do not change print rendering logic or Documint templates.
- Do not change API endpoint signatures.
Worktree Strategy
Section titled “Worktree Strategy”Two worktrees already exist at the workspace root. Both are on the same branch, targeting different repositories. This is a single-agent project — no additional worktrees needed.
| Worktree directory | Branch | Repository | Tasks |
|---|---|---|---|
extra-printing-options-worktrees/operations | jmpicnic/extra-printing-options-management-820 | operations | T-2 through T-11 |
extra-printing-options-worktrees/documentation | jmpicnic/extra-printing-options-management-820 | documentation | Goal, specification, verification, T-12 |
Spreadsheet tasks (T-1) are executed via Google Workspace MCP and do not require a worktree.
Risks and Mitigations
Section titled “Risks and Mitigations”| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
enumerationByName fails on new enum values for existing DB rows | Low | High | New values are additive; existing string names unchanged. Verify at T-8. |
| Protobuf wire compatibility broken by new field numbers | Low | High | New values appended after existing ones; UNSPECIFIED = 0 unchanged. |
| Breadcrumb X_SMALL/SMALL alias collision in CSV | — | Differentiated display names: “3 x 1 (xs Label Printer)” vs “3 x 1 (Label Printer)”. | |
| Spreadsheet MCP write fails mid-update | Low | Medium | Create new sheet (don’t modify existing); can retry from scratch. |
Frontend misinterprets active flag semantics | Low | Medium | Frontend ticket specifies exact behavior; backend stores flag but does not filter. |
Open Questions and Decisions
Section titled “Open Questions and Decisions”| # | Question | Options | Recommendation | Decision |
|---|---|---|---|---|
| 1 | Breadcrumb X_SMALL/SMALL share display name “3 x 1 (Label Printer)” — how to resolve? | A) Alias precedence; B) Differentiate display names | B) Differentiate: X_SMALL → “3 x 1 (xs Label Printer)”, SMALL → “3 x 1 (Label Printer)“ | B) Differentiate |
| 2 | Should active default to true or false in the data class? | A) true (backwards-compatible); B) false (explicit opt-in) | A) true — existing entries in JSON lack the field and should remain active | true |
| 3 | CHANGELOG version number | A) 2.20.0 (minor — additive); B) 2.19.5 (patch) | A) Minor bump — new enum values are additive feature | 2.20.0 |
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved