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

5.1 KiB

phase plan subsystem tags requires provides affects tech-stack key-files key-decisions duration completed
42-wallpapers-social-format-conversion-voice 03 api
sharp
ffmpeg-static
xlsx
csv-parse
file-type
convert-renderer
multipart
magic-byte
content-jobs
typescript
phase plan provides
42-wallpapers-social-format-conversion-voice 01 ConvertBundle type, convert case in renderContent switch, converter-capabilities service
phase provides
40-content-job-infra contentJobStore, contentJobRunner, async job pattern
server/src/services/renderers/convert-renderer.ts — full format conversion router (sharp/ffmpeg/xlsx/AI-bridge)
server/src/routes/convert.ts — POST /api/companies/:companyId/convert (multipart, 202)
server/src/routes/convert.ts — GET /api/system/converters (capability map)
convert route mounted in app.ts
42-06 (UI wiring — ConvertPanel calls these endpoints)
added patterns
ffmpeg-static stdin/stdout pipe pattern for audio/video conversion
csv-parse/sync for synchronous CSV parsing with column headers
xlsx.read/write for XLSX ↔ JSON ↔ CSV round-trips
fileTypeFromBuffer magic-byte MIME validation with text-based extension allowlist
multer memoryStorage + runSingleFileUpload wrapper (follows chat-files.ts pattern)
created modified
server/src/routes/convert.ts
server/src/services/renderers/convert-renderer.ts
server/src/app.ts
ffmpegPath cast as unknown as string required — ffmpeg-static typings return string|null but binary is always present; matches documented Pitfall 3 from research
TEXT_BASED_EXTENSIONS allowlist prevents false 422 rejections for CSV/JSON/SVG which have no magic bytes
sourceMime resolved from extension map rather than multer claim to avoid browser MIME inconsistencies
StorageService passed through to convertRoutes for future asset storage but not used in job dispatch path (job runner handles storage)
3min 2026-04-04

Phase 42 Plan 03: Format Conversion Renderer and Multipart Route

Full convert-renderer.ts routing sharp/ffmpeg/xlsx/AI-bridge by format pair, multipart upload route with magic-byte MIME validation returning 202, and GET /api/system/converters capability endpoint

Performance

  • Duration: 3 min
  • Started: 2026-04-04T22:12:21Z
  • Completed: 2026-04-04T22:15:16Z
  • Tasks: 2
  • Files modified: 3 (1 replaced, 1 created, 1 modified)

Accomplishments

  • Replaced stub convert-renderer.ts with full implementation routing four format categories:
    • Image pairs (PNG/JPG/WebP/GIF/SVG) → sharp with density:300 for SVG input
    • Audio/video pairs → ffmpeg-static via stdin/stdout pipe (ffmpegPath as unknown as string)
    • Data pairs (CSV/JSON/XLSX) → csv-parse/sync + xlsx for all six conversion combinations
    • All other pairs → AI-bridge via puterChatComplete with system prompt
  • Created convert.ts route with multer memoryStorage, fileTypeFromBuffer magic-byte validation, and 202 job dispatch
  • Implemented MIME mismatch detection: returns 422 with { error, actualMime, claimedMime } for misnamed binary files
  • Text-based formats (CSV, JSON, SVG, TXT, HTML, MD, XML) allowed through without magic-byte check (they return null)
  • Wired GET /api/system/converters endpoint returning converterCapabilitiesService result
  • Mounted convertRoutes in app.ts after contentJobRoutes

Task Commits

Each task was committed atomically:

  1. Task 1: Implement convert renderer with format routing - d5f7586d (feat)
  2. Task 2: Create multipart convert route with MIME validation and wire to app.ts - 84f97a43 (feat)

Files Created/Modified

  • server/src/services/renderers/convert-renderer.ts - Full implementation: isImageFormat/isAVFormat/isDataFormat helpers, convertImage/convertAV/convertData/convertViaAiBridge functions, renderConvert entry point
  • server/src/routes/convert.ts - Multipart upload route: multer, fileTypeFromBuffer MIME validation, content job dispatch, converter capability endpoint
  • server/src/app.ts - Import and mount convertRoutes after contentJobRoutes

Decisions Made

  • ffmpegPath as unknown as string cast used in spawn — ffmpeg-static typings declare string | null but the binary is always present when the package is installed; matches Pitfall 3 documented in 42-RESEARCH.md
  • TEXT_BASED_EXTENSIONS allowlist prevents false 422 rejection for text-based formats whose fileTypeFromBuffer returns null (no magic bytes)
  • Source MIME resolved from extension map rather than multer's file.mimetype to avoid browser-reported MIME inconsistencies (e.g. Chrome reports text/csv but Safari may report application/csv)

Deviations from Plan

None — plan executed exactly as written.

Known Stubs

None — all conversion paths are fully implemented.

Self-Check: PASSED

  • server/src/services/renderers/convert-renderer.ts — FOUND
  • server/src/routes/convert.ts — FOUND
  • Task 1 commit d5f7586d — FOUND
  • Task 2 commit 84f97a43 — FOUND
  • tsc --noEmit — zero errors