# Mail Merge Documents

## Objective

Build one document template with placeholders and generate a copy for every record.

A template with named placeholders plus a run that produces one rendered document per selected record.

## Before You Begin

This feature is being added to an application that already exists and already
works. Do not scaffold a new project, and do not assume a blank slate.

Inspect the codebase first and establish:

- The existing application structure and where code of this kind already lives.
- The framework and version in use.
- The existing design system — colours, spacing, typography, and component conventions.
- Existing UI components you can reuse instead of writing new ones.
- The existing database structure, if this feature needs to persist anything.
- The existing authentication and authorization system, if this feature is user-scoped.
- Dependencies already installed, so you don't add a library that duplicates one.
- The existing test setup and conventions.

Only start writing code once you understand the above. If the application
already implements part of this feature, extend it rather than replacing it.

## Implementation Instructions

1. Build the template on the app's existing editor and, if it has one, its Template Picker. Authors should not have to learn a second writing surface to add placeholders.
2. Offer placeholders from a defined list of fields on the record type being merged, inserted by picking rather than typed by hand, so a misspelt field name is not possible.
3. Render the output documents through the app's existing PDF Export path and deliver a large run as a single archive rather than as hundreds of separate downloads.
4. Run the merge as background work with progress, a per-record result, and the ability to retry only the records that failed.
5. Do not build a scripting language into the template. Substitution, a fallback value, and a simple present-or-absent section cover the real cases, and anything more becomes a security surface and a support burden.

## UI and UX Requirements

Match the application's existing design system exactly. Reuse its components,
spacing, and typography. This feature should look like it was always there.

## Responsive Requirements

Works on mobile, tablet, and desktop. Touch targets are large enough to hit on a
phone, and nothing overflows horizontally at 320px.

## Accessibility Requirements

- Fully keyboard navigable.
- Correct semantic elements and ARIA roles.
- Visible focus states.
- Meets WCAG AA contrast.
- Dynamic changes are announced to screen readers.
- Respects prefers-reduced-motion.

## Edge Cases

- A run started with placeholders the data cannot fill produces hundreds of documents with holes in them. Validate the template against the selected records first and show exactly which placeholders are unresolved and how many records are affected.
- A missing value must not leave a blank gap mid-sentence. Let the author set a fallback per placeholder, or omit the surrounding line entirely, and make the chosen behaviour visible in the editor.
- A run of several thousand records that fails at record 2900 must not discard the first 2899. Process in batches, record per-record status, and make the whole job resumable.
- Record data is user-supplied and will contain characters that mean something to the renderer. Escape every substituted value so a name containing markup cannot alter the layout, inject content into other documents, or execute anything.
- Generating hundreds of documents to discover a broken layout wastes time and money. Require a single-record preview against real data before the full run can be started.
- Placeholders inside tables, headers, and repeated blocks behave differently from ones in body text and are the usual source of misaligned output. Test those positions specifically.
- Long substituted values will overflow a line designed around a short one. Define wrapping behaviour rather than letting text run off the page.
- Each generated document inherits the access rules of the record it came from. A merge output must not be readable by anyone who could not read the source record.

## Testing

Exercise the feature end to end in the running application. Cover every edge case
above, then run the existing test suite and confirm nothing regressed.

## Acceptance Criteria

- [ ] A template with picked placeholders generates one document per selected record.
- [ ] Unfilled placeholders are reported with affected record counts before the run starts.
- [ ] Missing values resolve to a defined fallback or an omitted line, never a blank gap.
- [ ] Large runs process in batches with per-record status and retry of failures only.
- [ ] Substituted values are escaped and cannot alter the template or output.
- [ ] A single-record preview is required before a full run.
- [ ] Generated documents inherit the access rules of their source records.
- [ ] The feature matches the existing design system.
- [ ] No existing functionality is broken.

## Adaptation Rules

- Match the existing design system. Do not introduce a new colour palette,
  spacing scale, or component library.
- Reuse existing components and utilities wherever they fit.
- Follow the naming, file layout, and code style already present.
- Do not upgrade, replace, or remove existing dependencies to make this
  feature fit. Adapt the feature to the app, not the app to the feature.
- Do not break existing functionality. If a change is genuinely required in
  existing code, make the smallest one that works and say so.
- If something in these instructions conflicts with how the application is
  built, follow the application and explain the deviation.

## Final Verification

Before you report the work as done:

1. Re-read the acceptance criteria above and check each one against what you
   actually built.
2. Run the application and exercise the feature end to end.
3. Run the existing test suite and confirm you have broken nothing.
4. Check the feature on mobile, tablet, and desktop widths.
5. Check keyboard navigation and focus handling.
6. Summarize what changed: files added, files modified, and anything you
   deliberately did differently because of how this application is built.

If any acceptance criterion is unmet, fix it before reporting completion.
