# PDF Converter

## Objective

Let people turn the files they upload into PDFs, and PDFs back into editable formats.

A conversion service that accepts an uploaded document and returns it in a requested format, with progress and a downloadable result.

## 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. Start from the app's existing upload path rather than adding a second one. If File Upload, Upload Malware Scanning, or Secure File Downloads already exist, the converter consumes what upload produces and hands its output to the existing download route, so permissions and scanning are inherited rather than reimplemented.
2. Decide the conversion pairs you will actually support and list them in the interface. A short honest list of office documents, images, and PDF to text beats a control that offers every combination and fails on most of them.
3. Enforce file size, page count, and accepted types on the server before any conversion starts. A limit checked after the file has been parsed has already cost you the memory and the CPU you were trying to protect.
4. Run every conversion in the app's existing background job system and show the user a progress state with a cancel control, rather than holding an HTTP request open until the work finishes.
5. Do not build a general-purpose document engine or attempt to preserve every layout feature. Convert the common cases faithfully, and tell the user plainly which parts of the original did not survive.

## 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

- Size and page-count limits must be checked before conversion begins, not after. A two-thousand-page document rejected at the end has already consumed the worker that other users were queued behind.
- A synchronous conversion will time out on anything real. Queue the work, return immediately with a job the user can watch, and let the result appear when it is ready rather than blocking the request.
- Fonts, embedded images, and page breaks all drift during conversion. Preserve them where you can, and when fidelity is lost say so on the result screen instead of handing back a mangled file with no explanation.
- Password-protected sources cannot be opened without the password, and corrupt files will crash the parser. Both must fail as a single item with a clear reason, leaving the rest of a multi-file batch to finish.
- Converted output and the original upload both linger on disk. Set a retention window, delete intermediate artefacts on a schedule, and make the expiry visible so a conversion tool does not quietly become a document archive nobody audited.
- The download link for a converted file must check the same permissions as the source. A guessable result URL turns every conversion into a public copy of a private document.
- The same file converted twice should not be converted twice. Key the job on the file contents and the target format so a user clicking again gets the existing result.
- A conversion that produces a zero-byte or unreadable output must be reported as a failure. Do not let an empty file through as a success because the process exited cleanly.

## 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

- [ ] Size, page count, and file type are rejected server-side before any conversion work starts.
- [ ] Conversions run in the background with visible progress and a working cancel.
- [ ] Password-protected and corrupt files fail individually with a readable reason, and the rest of the batch completes.
- [ ] Fidelity loss is reported on the result rather than left for the user to discover.
- [ ] Source files and intermediate artefacts are deleted on a stated schedule.
- [ ] Downloading a converted file enforces the same access rules as the original upload.
- [ ] The converter reuses the app's existing upload, scanning, and download paths rather than a parallel set.
- [ ] 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.
