# Resource Transfer (Non-Character) — Implementation Plan

## Scope

### In scope
- Add **Transfer** support and UI to these resource types:
  - **Looks**
  - **Outfits**
  - **Actions**
  - **Styles**
  - **Scenes**
  - **Detailers**

### Out of scope / explicitly excluded
- **Characters** (existing flow may remain separate)
- **Checkpoints**
- **Presets**

## User experience requirements

### Entry points
- A **Transfer** button should appear on **all supported resource detail pages**.
- Clicking **Transfer** opens a transfer form for the currently viewed resource.

### Transfer form fields
The form must allow the user to:
- Select **target category** (destination resource type)
- Edit **new name**
- Edit **new id/slug**
- Optionally choose **Use LLM** to regenerate JSON (recommended default: enabled)

All of these fields should be **pre-populated using the existing resource’s information**.

### Post-submit behavior
- After transfer completes, redirect to the **target category index page** (e.g. `/looks`).
- **Highlight** the newly created item on the index page.
- Do **not** auto-generate previews/covers.

## Current state (reference implementation)

- Character-only transfer route exists: [`transfer_character()`](../app.py:2216)
- Character detail page shows Transfer in header: [`templates/detail.html`](../templates/detail.html:79)
- Resource detail templates do not currently show Transfer (examples):
  - Looks: [`templates/looks/detail.html`](../templates/looks/detail.html:123)
  - Outfits: [`templates/outfits/detail.html`](../templates/outfits/detail.html:118)
  - Actions: [`templates/actions/detail.html`](../templates/actions/detail.html:129)

## Proposed backend design

### 1) Add a generic resource transfer route
Implement a category-based route:

- `GET|POST /resource/<category>/<slug>/transfer`

Responsibilities:
- Validate `category` is in allowlist: `looks,outfits,actions,styles,scenes,detailers`
- Load the appropriate SQLAlchemy model instance by `slug`
- Render a resource-agnostic transfer form on GET
- On POST:
  - Validate new name/id constraints
  - Generate a safe/unique slug for the destination category
  - Create destination JSON (LLM path or non-LLM fallback)
  - Write JSON file to correct `data/<category>/` directory
  - Create DB row for the new resource
  - Redirect to destination index with highlight

### 2) Shared mapping table
Create a mapping table/dict:
- `category → model_class`
- `category → target_dir`
- `category → id_field` (e.g. `look_id`, `outfit_id`, ...)
- `category → index_route` (e.g. `looks_index`)

This mirrors the `target_type` mapping approach in [`transfer_character()`](../app.py:2251).

## JSON generation strategy

### LLM path (primary)
- Use an explicit transfer prompt (existing code loads `transfer_system.txt` in [`transfer_character()`](../app.py:2289)).
- Provide the source resource JSON as input context.
- Instruct the LLM:
  - to output **JSON only** (no markdown)
  - to conform to the **target resource schema**
- After parsing:
  - enforce required fields: `<target>_id` and `<target>_name` (pattern used in [`transfer_character()`](../app.py:2316))

### Non-LLM fallback
- Create a minimal template JSON for the target type.
- Copy safe common fields where present (e.g. `tags`, `lora`).
- Add a provenance description like “Transferred from <source>”.

## Frontend changes

### 1) Add Transfer button to supported resource detail pages
Add a Transfer button near existing header actions, pointing to `/resource/<category>/<slug>/transfer`.

Targets:
- [`templates/looks/detail.html`](../templates/looks/detail.html:123)
- [`templates/outfits/detail.html`](../templates/outfits/detail.html:118)
- [`templates/actions/detail.html`](../templates/actions/detail.html:129)
- [`templates/styles/detail.html`](../templates/styles/detail.html:1)
- [`templates/scenes/detail.html`](../templates/scenes/detail.html:1)
- [`templates/detailers/detail.html`](../templates/detailers/detail.html:1)

### 2) Highlight the new item on the destination index
Redirect scheme:
- `/looks?highlight=<slug>` (similar for each category)

Index templates to update:
- [`templates/looks/index.html`](../templates/looks/index.html:1)
- [`templates/outfits/index.html`](../templates/outfits/index.html:1)
- [`templates/actions/index.html`](../templates/actions/index.html:1)
- [`templates/styles/index.html`](../templates/styles/index.html:1)
- [`templates/scenes/index.html`](../templates/scenes/index.html:1)
- [`templates/detailers/index.html`](../templates/detailers/index.html:1)

Implementation idea:
- Add `data-slug="..."` to each item card/container and a small script that:
  - reads `highlight` query param
  - finds the element
  - scrolls into view
  - applies a temporary CSS class (e.g. `highlight-pulse`)

## Validation & error handling

- Reject invalid/unsupported categories.
- Enforce name length limits (existing character transfer uses `<= 100` in [`transfer_character()`](../app.py:2228)).
- Sanitize id/slug to safe filename characters.
- Ensure destination JSON filename is unique; if exists, auto-suffix `_2`, `_3`, ...
- LLM error handling:
  - JSON parse failures should show a user-facing flash message
  - preserve form inputs on redirect if possible

## Testing

Add tests covering:
- Happy path transfer for one representative resource (e.g. look → outfit)
- Invalid category rejected
- Duplicate slug resolution works
- LLM returns invalid JSON → proper failure handling

## Deliverables checklist

- New transfer route and supporting helper mapping in app backend
- Resource-agnostic transfer template
- Transfer button on all supported detail pages
- Index page highlight behavior
- Prompt file verified/added for transfer conversions
- Tests + minimal docs update
