nexus/.planning/phases/42-wallpapers-social-format-conversion-voice/42-06-SUMMARY.md

130 lines
6.6 KiB
Markdown

---
phase: 42-wallpapers-social-format-conversion-voice
plan: 06
subsystem: ui
tags: [react, typescript, drag-drop, format-conversion, deep-link, SSE, FormData, multipart, shadcn, lucide]
# Dependency graph
requires:
- phase: 42-wallpapers-social-format-conversion-voice
plan: 03
provides: POST /api/companies/:companyId/convert (multipart), GET /api/system/converters, ConvertBundle type
- phase: 40-content-job-infra
provides: useContentJob hook, getContentJobAsset, SSE job tracking pattern
provides:
- ui/src/api/convert.ts — submitConvertJob (multipart) and getConverterCapabilities API client
- ui/src/components/ConvertPanel.tsx — drag-drop + grouped format chips + AI fallback notice + download
- ui/src/pages/ConvertPage.tsx — /convert route with deep-link URL param reading
- ui/src/App.tsx — three route variants /convert, /convert/:src, /convert/:src/:tgt
affects:
- Any future phase adding nav links to /convert
# Tech tracking
tech-stack:
added: []
patterns:
- Direct fetch (not api.post) for multipart submissions that need per-status-code inspection (422 vs 202)
- Direct EventSource connection for pre-submitted jobs (bypasses useContentJob.submit which re-submits)
- FORMAT_GROUPS constant exported from ConvertPanel for reuse in ConvertPage validation
- normalizeFormatParam helper: toLowerCase + allowlist check, silently returns undefined for invalid params
key-files:
created:
- ui/src/api/convert.ts
- ui/src/components/ConvertPanel.tsx
- ui/src/pages/ConvertPage.tsx
modified:
- ui/src/App.tsx
key-decisions:
- "Direct fetch used in submitConvertJob (not api.postForm) to inspect 422 vs 202 status before throwing — api.request() throws on !res.ok, but 422 is a valid business response with MIME error body"
- "Direct EventSource in ConvertPanel for already-submitted jobs — useContentJob.submit() calls submitContentJob internally and cannot track an existing jobId without re-submitting"
- "FORMAT_GROUPS exported from ConvertPanel so ConvertPage can import the same constant for allowlist validation without duplicating the list"
- "AI fallback notice shown per target format group (Images/AV/Docs/Data) based on capabilities, not per individual format pair — matches CONV-08 spec that all paths fall to AI bridge when direct converter unavailable"
patterns-established:
- "Format chip role=radio within role=radiogroup — matches accessibility spec from 42-UI-SPEC.md"
- "Drop zone uses motion-safe: Tailwind variant to disable transition for prefers-reduced-motion"
requirements-completed: [CONV-01, CONV-02, CONV-03, CONV-04, CONV-05, CONV-06, CONV-07, CONV-08, CONV-09]
# Metrics
duration: 12min
completed: 2026-04-04
---
# Phase 42 Plan 06: Format Conversion UI Summary
**Drag-drop ConvertPanel with grouped format chips, AI fallback notice, MIME error display, SSE job tracking, and deep-link /convert/:src/:tgt routing**
## Performance
- **Duration:** 12 min
- **Started:** 2026-04-04T22:17:33Z
- **Completed:** 2026-04-04T22:29:00Z
- **Tasks:** 2
- **Files modified:** 4 (3 created, 1 modified)
## Accomplishments
- Created convert.ts API client: submitConvertJob with direct fetch for 422/202 status differentiation; getConverterCapabilities for startup capability probe
- Built ConvertPanel with all three visual zones: ConvertSourceZone (drag-drop with idle/dragover/error states), ConvertTargetSelector (grouped chips with AI fallback notice), ConvertActionBar (disabled until ready, download after done)
- FORMAT_GROUPS constant drives chip rendering and is exported for ConvertPage format validation
- ConvertPage reads URL params, normalizes to lowercase, silently ignores invalid format strings
- Three route variants wired in App.tsx: /convert, /convert/:sourceFormat, /convert/:sourceFormat/:targetFormat
## Task Commits
1. **Task 1: Create convert API client and ConvertPanel component** - `c0040f66` (feat)
2. **Task 2: Create ConvertPage and wire routes in App.tsx** - `b5587c03` (feat)
## Files Created/Modified
- `ui/src/api/convert.ts` - submitConvertJob (multipart POST, 422/202 handling), getConverterCapabilities
- `ui/src/components/ConvertPanel.tsx` - Full ConvertPanel: drag-drop zone, FORMAT_GROUPS chips, AI fallback notice, SSE progress, download
- `ui/src/pages/ConvertPage.tsx` - Route page reading sourceFormat/targetFormat URL params with case-insensitive normalization
- `ui/src/App.tsx` - Added ConvertPage lazy import and three /convert route variants inside boardRoutes()
## Decisions Made
- **Direct fetch in submitConvertJob** — api.request() throws on any !res.ok response, but 422 is a valid business response carrying the MIME mismatch error body. Using raw fetch lets us return it as a ConvertMimeError value instead of catching and re-parsing an ApiError.
- **Direct EventSource for pre-submitted jobs** — useContentJob.submit() calls submitContentJob internally; it has no "track existing job" API. Since submitConvertJob already dispatched the convert job via the multipart route (not contentJobs route), a standalone EventSource connection is used to track progress.
- **FORMAT_GROUPS exported from ConvertPanel** — ConvertPage needs the same allowlist for normalizeFormatParam validation. Exporting from ConvertPanel avoids duplication and keeps them in sync.
- **AI fallback notice per group** — The capabilities object returns converter availability per category (imageConverter, audioVideoConverter, docConverter, dataConverter), not per format pair. Showing the notice at group level matches the granularity available from /api/system/converters.
## Deviations from Plan
None — plan executed exactly as written.
## Known Stubs
None — all conversion flows are fully wired to real backend endpoints.
## Issues Encountered
None — tsc compiles cleanly for all new/modified files. 17 pre-existing errors in unrelated files (AgentConfigForm, useKeyboardShortcuts, useNexusMode, usePiperTts, useVadRecorder, ContentStudio, PersonalAssistant) were present before this plan and not introduced here.
## User Setup Required
None — no external service configuration required.
## Next Phase Readiness
- All CONV requirements fulfilled (CONV-01 through CONV-09)
- /convert, /convert/:src, and /convert/:src/:tgt routes live and navigable
- Phase 42 is complete — all 6 plans executed
---
*Phase: 42-wallpapers-social-format-conversion-voice*
*Completed: 2026-04-04*
## Self-Check: PASSED
- `ui/src/api/convert.ts` — FOUND
- `ui/src/components/ConvertPanel.tsx` — FOUND
- `ui/src/pages/ConvertPage.tsx` — FOUND
- `.planning/phases/42-wallpapers-social-format-conversion-voice/42-06-SUMMARY.md` — FOUND
- Task 1 commit `c0040f66` — FOUND
- Task 2 commit `b5587c03` — FOUND