# Lemon Squeezy License Sync

## Objective

Sync Lemon Squeezy orders and license keys into the app's entitlement state.

A verified event pipeline mapping Lemon Squeezy orders, subscriptions, and license keys onto local entitlements, with activation limits and revocation handled.

## 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. Verify the authenticity of every incoming provider event before it changes anything. An unverified purchase notification is a request from the internet to give away your product.
2. Keep an explicit server-side table mapping each purchasable variant to the entitlement it grants. Do not infer the plan from a product name, because names get edited for marketing reasons and entitlements should not move when they do.
3. Bind each license key to a single account on first activation and refuse to activate it against a different one afterwards, with a documented path for an operator to release a key that genuinely needs to move.
4. Track activations against the key's own limit, and treat deactivation as returning a slot rather than deleting the record, so an audit can show where a key has been used.
5. Entitlement must live in the same local access record any other billing brief writes to. If a Stripe or Paddle brief is also applied, this one adds a source, it does not add a second source of truth.

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

- Events arriving without a valid signature must be rejected outright, and rejections logged. Nothing is activated on the strength of an unverified message.
- Variants and products map to entitlements through explicit server-side configuration. An unrecognised variant must park the order for an operator rather than defaulting to some plan, and a mapping change must not silently upgrade existing customers.
- Activation limits, deactivations, expiry, and refunded or charged-back orders all have to revoke or restore access correctly. A refund that leaves the license working is a hole; a refund that also deletes the customer's data is worse.
- Provider deliveries are retried. Record processed event identifiers and make handlers repeat-safe, or a retry will grant a second seat or send a second receipt.
- A license key must not attach to an unrelated account. Bind on first activation, reject mismatches, and require an explicit operator action with a record of who did it to reassign one.
- Out-of-order delivery means a cancellation can arrive before the renewal that supersedes it. Compare against a stored sequence or timestamp and ignore anything older than current state.
- When the provider is unreachable, previously activated licenses must keep working. Offline validation should fall back to the last known good state with a grace period rather than locking paying users out.
- Never expose the provider credential or the raw license key in client-visible code, and show keys to the owner only, masked until deliberately revealed.

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

- [ ] Unsigned or unverifiable events are rejected and logged, and change no state.
- [ ] Variants map to entitlements through explicit server configuration, and unknown variants are quarantined.
- [ ] Activation limits are enforced, deactivation returns a slot, and the activation history is retained.
- [ ] Refunds, expiry, and cancellations revoke access without destroying the customer's data.
- [ ] Retried and out-of-order deliveries leave entitlement state correct.
- [ ] A license key is bound to one account and can be reassigned only by a recorded operator action.
- [ ] Provider unavailability leaves existing licenses working within a defined grace period.
- [ ] 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.
