Commit Graph
100 Commits
Author SHA1 Message Date
anthony 6fc3386965 fix(seo): pass lang as a prop to Header/LanguageSwitcher instead of useParams
Since the vite-react-ssg migration replaced the dynamic /:lang route param
with literal /fr and /en routes, useParams().lang always returned undefined
here, breaking the header brand link (linked to /undefined/) and silently
breaking the language switcher (always resolved otherLang to 'fr').
2026-08-02 10:58:23 +02:00
anthony 74c676df9f specs 2026-08-02 10:57:41 +02:00
anthony 3a9836d58b feat(seo): add video and audio conversion pages 2026-08-02 10:39:08 +02:00
anthony 04b792c454 feat(seo): add remaining document conversion pages 2026-08-02 10:36:59 +02:00
anthony 0e19f92cda feat(seo): add remaining image, HEIC, and ICO conversion pages 2026-08-02 10:35:11 +02:00
anthony e6ab78de29 feat(seo): add conversion-page scaffolding with 2 seed pairs (jpg-to-png, pdf-to-docx) 2026-08-02 10:32:53 +02:00
anthony 3b53d82b3d feat(seo): migrate to build-time prerendering with vite-react-ssg
Fixes SeoHead (title/canonical/hreflang/JSON-LD) to render during SSR via
vite-react-ssg's Head component instead of a client-only useEffect, so
crawlers see real tags without executing JS. Also fixes an SSR crash in
useTheme (localStorage access with no window during server render) and
removes now-duplicated static meta tags from index.html.
2026-08-02 10:30:26 +02:00
anthony 8dcc5f3405 chore(frontend): downgrade react-router-dom to v6 for vite-react-ssg compatibility 2026-08-02 10:24:43 +02:00
anthony c07663aa7b feat(seo): return a real 404 status for unmatched routes 2026-08-02 10:23:07 +02:00
anthony b2636e20cf feat(seo): redirect / to /fr/ or /en/ server-side based on Accept-Language 2026-08-02 10:21:38 +02:00
anthony 5ff8a865e8 feat(seo): add compression, cache-control headers, configurable frontend dist path 2026-08-02 10:20:22 +02:00
anthony 26433fa9c7 docs: add implementation plan for SEO fixes and prerendering migration
11 tasks: Express fixes (compression/cache/redirect/404), react-router-dom
v6 downgrade (required for vite-react-ssg compatibility, verified via
dry-run), vite-react-ssg prerendering migration, and 30 curated
conversion-pair landing pages with real fr/en content.
2026-08-02 10:13:28 +02:00
anthony 9d30ff4c74 docs: add design spec for SEO fixes and prerendering migration
Covers server-side redirects/404, compression/cache headers, dynamic
sitemap, vite-react-ssg prerendering with react-helmet-async, and 30
curated conversion-pair landing pages.
2026-08-02 09:51:40 +02:00
anthonyandClaude Sonnet 5 afb0fed650 feat(video): add video format family, resolution control, and marquee pair
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 09:07:23 +02:00
anthonyandClaude Sonnet 5 770d2c9bdc feat(infra): add docker-compose for local MariaDB with Prisma schema init
Applies prisma/migrations/*/migration.sql on first container boot via a
sourced docker-entrypoint-initdb.d script, so a fresh container matches a
`prisma migrate deploy` run without needing shadow-database privileges.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-02 09:05:36 +02:00
anthonyandClaude Sonnet 5 457913d8d4 feat(video): wire video converters, resolution validation, and timeout into app.js/worker.js
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 22:01:58 +02:00
anthonyandClaude Sonnet 5 9c1f857398 feat(video): add MIME types for mp4/webm/mov/avi/mkv
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:59:06 +02:00
anthonyandClaude Sonnet 5 913dbac691 feat(video): add ffmpeg-backed video converter for mp4/webm/mov/avi/mkv
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:58:23 +02:00
anthonyandClaude Sonnet 5 886c2e8539 feat(video): add configurable VIDEO_JOB_TIMEOUT_MS
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:57:37 +02:00
anthonyandClaude Sonnet 5 a92556808a docs(video): add implementation plan for video conversion feature
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:53:56 +02:00
anthonyandClaude Sonnet 5 728247a2cf docs(video): refine spec with verified file-type detection and simplified converter
Verified exact file-type v22 magic-byte detection for all 5 formats against
real fixture buffers (no normalizeFormat aliases needed), and simplified the
converter's resolution-scaling gate to match audio.js's validation-boundary
pattern (app.js range-checks, converter trusts the value).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 21:51:50 +02:00
anthonyandClaude Sonnet 5 69b3de8031 docs(video): add design spec for video conversion feature
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 15:23:49 +02:00
anthony 3775d34a22 feat(audio): add bitrate chip control, default bitrates, and marquee pair 2026-08-01 14:22:40 +02:00
anthony 3d62d2983b feat(audio): recognize the audio family in the frontend formats grid 2026-08-01 14:19:39 +02:00
anthony 433ff3b726 feat(audio): add MIME types for mp3/wav/ogg/flac/aac/m4a 2026-08-01 14:17:25 +02:00
anthony 050ea5ba64 feat(audio): wire audio converters and bitrate validation into app.js/worker.js 2026-08-01 14:15:13 +02:00
anthony 05be353664 feat(audio): add ffmpeg-backed audio converter for mp3/wav/ogg/flac/aac/m4a 2026-08-01 14:13:09 +02:00
anthony 13d095aa4c docs: add audio conversion implementation plan 2026-08-01 13:41:00 +02:00
anthony aa5383d7f0 docs: fix m4a mime type and document exact file-type detection bytes 2026-08-01 13:38:48 +02:00
anthony a23ccf465c docs: add audio conversion design spec 2026-08-01 13:34:44 +02:00
anthonyandClaude Sonnet 5 74db0ecfcc feat(frontend): add archive pair to the homepage format marquee
Every other family (images, documents, fonts, ebooks) had a showcase
pair in the marquee; archives was missing one after the archive
conversion feature landed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 13:09:38 +02:00
anthonyandClaude Sonnet 5 48c70254c1 feat(frontend): add archive format family, compression control, and fixed double-extension parsing
Also adds a --color-family-archives CSS variable (light + dark) that
the plan didn't call out explicitly but is needed for the new family
tile/icon to render with a color instead of falling back silently.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 13:03:30 +02:00
anthonyandClaude Sonnet 5 ef6de6b583 feat(archive): wire archive converters, validation, and extension parsing into app.js/worker.js
Also fixes a third double-extension bug the plan missed: app.js derived
each job's uuid via path.basename(file.filename, path.extname(...)),
which only strips the last dot segment. For a compound extension like
tar.gz this left "<uuid>.tar" as the "uuid", overflowing the uuid
column (Char(36)) and crashing the request. Replaced with
stripExtension(). Also bumped rateLimitMaxJobs in jobs.test.js's config
override — the file's cumulative POST /api/jobs calls across all tests
now exceeds the production default (20/window) once the archive tests
are included, causing spurious connection resets independent of any
real bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 13:00:01 +02:00
anthonyandClaude Sonnet 5 a8cdb06d5c feat(archive): add MIME types and compound-extension aliases for archive formats
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 12:55:56 +02:00
anthonyandClaude Sonnet 5 ceddeddf3e feat(archive): add rar extraction support
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 12:55:10 +02:00
anthonyandClaude Sonnet 5 a66143d312 feat(archive): add 7z and tar.7z converters
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 12:53:36 +02:00
anthonyandClaude Sonnet 5 a76b10a43f feat(archive): add tar.bz2 converter via 7za
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 12:52:29 +02:00
anthonyandClaude Sonnet 5 c9251e66e2 feat(archive): add tar and tar.gz converters
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 12:51:34 +02:00
anthonyandClaude Sonnet 5 d68694ead8 feat(archive): add zip converter with compression level and zip-slip protection
archiver v8 (installed) uses a class-based API (`ZipArchive`) rather than
the factory-function API most examples online still describe — adjusted
createZip() to match after the first test run surfaced the mismatch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 12:49:46 +02:00
anthonyandClaude Sonnet 5 031df9a999 feat(archive): add double-extension-aware filename parsing helper
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-01 12:47:27 +02:00
anthonyandClaude Sonnet 5 a7a91a7a2e feat(frontend): add remove button to pending and submitted file cards
Lets users drop an uploaded file from the UI list before or after
conversion, without cancelling anything server-side.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 16:47:18 +02:00
anthonyandClaude Sonnet 5 987af80286 feat(frontend): redesign homepage and file config form with aurora palette
Rebuild the visual identity from the actual Ombrora mark (violet/cyan aurora
blobs) instead of the generic blue/amber scheme, add Bricolage Grotesque and
IBM Plex Mono for display and code-like text, and give the hero an animated
aurora backdrop, gradient headline, and a format-pair marquee driven by the
real registered converters.

Rework the file config form: target format and icon size are both chip
groups now instead of a native select, and quality/compression sliders get a
gradient-filled track, custom thumb, and a mono value pill to match. File
type icons are color-coded by family (images/documents/fonts/ebooks) and
reused across FileConfigCard, FileCard, and FormatsGrid.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 16:34:13 +02:00
anthonyandClaude Sonnet 5 023a96e5d8 feat(frontend): show destination format badge, fix download size to reflect converted output
The download button was showing the input file's size (carried over
client-side from upload) instead of the actual converted file's size.
It now reads outputSizeBytes from the polled job status once done.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 16:14:44 +02:00
anthonyandClaude Sonnet 5 db3e73860b feat(api): expose outputSizeBytes on job status
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 16:14:38 +02:00
anthonyandClaude Sonnet 5 89749d8c20 fix(frontend): show file size in the download button label
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 16:10:29 +02:00
anthonyandClaude Sonnet 5 a647bee507 feat(frontend): thread file size from upload through to the download card
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 16:04:01 +02:00
anthonyandClaude Sonnet 5 f1f7a0162d feat(frontend): add icon/size header, spinner, and styled download button to FileCard
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 16:02:06 +02:00
anthonyandClaude Sonnet 5 994d70aa62 feat(frontend): restyle format picker and add file size to the config card
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 16:01:37 +02:00
anthonyandClaude Sonnet 5 7c58e50c11 feat(frontend): use flag icons in the language switcher
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 15:59:39 +02:00
anthonyandClaude Sonnet 5 f5958586b7 feat(frontend): add formatBytes util for human-readable file sizes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 15:53:03 +02:00
anthonyandClaude Sonnet 5 3cff496a85 feat(frontend): add flag-icons dependency
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 15:52:37 +02:00
anthonyandClaude Sonnet 5 d0ff81344f docs: add design spec for file card / language switcher polish
Covers flag-icons for the language switcher, a shared header layout
across the choose/convert/download states, human-readable file sizes,
and restyled format/quality controls and download button.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 15:43:46 +02:00
anthony 005bb0e2a7 package.json > fix npm run deploy for prisma 2026-07-31 15:32:44 +02:00
anthony 9d2a966431 docs: document o2switch's single package.json/node_modules constraint
Explains the react-router-dom resolution failure encountered deploying
the frontend redesign, and the fix (mirror frontend runtime deps into
root package.json) so it doesn't need re-discovering next time.
2026-07-31 15:27:46 +02:00
anthony 4e58568ddd fix(deploy): mirror frontend runtime deps into the root package.json
The o2switch nodevenv/Passenger setup only installs a single
package.json/node_modules (root), so npm install --prefix frontend
never actually populates frontend/node_modules there. Node's module
resolution walks up from frontend/src to the root node_modules, so
adding react-router-dom, react-i18next, i18next, and
@phosphor-icons/react to root's dependencies (react/react-dom were
already present) lets the production vite build resolve them without
needing a second node_modules tree.
2026-07-31 15:26:16 +02:00
anthony 965b2ecc53 style(frontend): responsive polish pass for narrow viewports
Part of the Ombrora Convert redesign (Task 5/5).
2026-07-31 15:00:18 +02:00
anthony 8e405bd3b0 feat(frontend): add per-language SEO metadata, JSON-LD, robots.txt, and sitemap
Part of the Ombrora Convert redesign (Task 4/5).
2026-07-31 14:59:06 +02:00
anthony 2aa8e51b80 feat(frontend): add reassurance strip and supported-formats section
Part of the Ombrora Convert redesign (Task 3/5).
2026-07-31 14:57:46 +02:00
anthony bc7a3b0691 feat(frontend): add routing, layout, i18n wiring, and restyle the conversion tool
Migrates the existing upload/format-select/quality/convert logic from
the old single-file App.jsx into a router shell (/ -> /fr//en/) with a
shared Layout (header, language switcher, dark-mode toggle, footer).
Tool logic itself is unchanged, only restyled into cards.

Part of the Ombrora Convert redesign (Task 2/5).
2026-07-31 14:55:16 +02:00
anthony ee18cc2d90 feat(frontend): add design tokens, dark mode hook, and i18n scaffold
Part of the Ombrora Convert redesign (Task 1/5).
2026-07-31 14:49:19 +02:00
anthony f499196dae docs: add Ombrora Convert frontend redesign implementation plan
5-task plan: design tokens/dark mode/i18n scaffold, routing+layout+
migrated tool, reassurance+formats sections, SEO metadata, responsive
polish.
2026-07-31 14:37:05 +02:00
anthony ab95e3e699 docs: add Ombrora Convert frontend redesign design spec
Foundation sub-project: merged homepage+tool page, FR/EN i18n via URL
prefix, dark mode, SEO basics, and reassurance elements backed by
actual backend guarantees (1h auto-delete, 100MB max, no account).
2026-07-31 14:27:15 +02:00
anthony 5850ca2c68 README.md > Add ffmpeg portable o2switch setup 2026-07-31 14:01:27 +02:00
anthony d811eb0abc README.md > Add Calibre Deploy Method 2026-07-31 13:54:56 +02:00
anthony dd8557e418 docs: add ebook conversion implementation plan 2026-07-31 13:29:11 +02:00
anthony 86b555b334 feat: register ebook converter in the app so the API serves the new family
Also fixes a real bug found via the fb2 API test: file-type sniffs a
real fb2 file's XML declaration as generic "xml", not "fb2" and not
undetected, so it never reached the undetectable-format fallback added
in the previous commit. Added an fb2->xml alias in normalizeFormat,
same pattern as the existing azw3->mobi one.
2026-07-31 13:29:06 +02:00
anthony 977dac35d9 feat: add ebook MIME types, fix azw3/mobi detection collision, trust undetectable ebook formats 2026-07-31 13:25:46 +02:00
anthony 534630ab4e feat: give ebook conversions their own worker timeout and register the converter 2026-07-31 13:24:49 +02:00
anthony f796c0bd97 feat: add configurable ebookJobTimeoutMs to config 2026-07-31 13:23:30 +02:00
anthony b95e371989 feat: add ebook converter wrapping Calibre's ebook-convert CLI 2026-07-31 13:23:01 +02:00
anthony 0cef6842de docs: add ebook conversion design (Calibre ebook-convert wrapper) 2026-07-31 13:13:49 +02:00
anthonyandClaude Sonnet 5 e7c30202f5 feat: register font/dfont converters in the app and worker
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 12:59:19 +02:00
anthonyandClaude Sonnet 5 be50f1f076 feat: add font MIME types and fix dfont/ico detection collision
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 12:57:35 +02:00
anthonyandClaude Sonnet 5 2cde4ec035 feat: add source-only dfont font converter
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 12:56:13 +02:00
anthonyandClaude Sonnet 5 e5e4f31e9b feat: add bidirectional ttf/otf/woff font converter
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 12:55:19 +02:00
anthonyandClaude Sonnet 5 b61e6e2df3 feat: add font conversion dependencies and test fixtures
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 12:54:32 +02:00
anthony 1eb391242f Add implementation plan for font conversion (ttf/otf/woff/dfont)
Five TDD tasks: dependencies+fixtures, ttf/otf/woff converter,
dfont extraction converter, mime.js fixes, and wiring+API tests.
2026-07-31 10:58:53 +02:00
anthony eb211d5672 Fix fontkit import in font conversion spec
Verified empirically: fontkit has no default ESM export in this project's
"type": "module" setup (import fontkit from 'fontkit' throws). The working
form is import * as fontkit from 'fontkit'.
2026-07-31 10:53:07 +02:00
anthony bd13bc1c9a Add design spec for font conversion (ttf/otf/woff/dfont; cff/cid dropped)
Empirically verified library choices (fonteditor-core, opentype.js, fontkit)
against real fonts before committing to the scope, and root-caused a
file-type/dfont MIME collision that would otherwise silently break uploads.
2026-07-31 10:50:44 +02:00
anthonyandClaude Sonnet 5 25a95f1ea3 feat: add ICO size picker to the upload UI
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:18:07 +02:00
anthonyandClaude Sonnet 5 598781f417 feat: register ICO/HEIC/HEIF converters in the worker and pass iconSize through
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:16:25 +02:00
anthonyandClaude Sonnet 5 67bdfbf3de feat: wire ICO/HEIC/HEIF converters and iconSize validation into the API
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:15:14 +02:00
anthonyandClaude Sonnet 5 be43eac13a feat: thread iconSize through jobRepository
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:13:15 +02:00
anthonyandClaude Sonnet 5 1ff660a3d2 feat: add iconSize column to ConversionJob
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:12:32 +02:00
anthonyandClaude Sonnet 5 8795f65055 feat: add source-only HEIC/HEIF image converter
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:10:41 +02:00
anthonyandClaude Sonnet 5 05ef7dfca1 feat: add bidirectional ICO image converter
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:09:56 +02:00
anthonyandClaude Sonnet 5 39b296f5d3 feat: add ico MIME type and heif->heic extension alias
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 10:08:46 +02:00
anthony 2b2d8a9e6f Add implementation plan for HEIC/HEIF/ICO image format support
9 tasks covering mime.js, the ico/heic converter modules, a new
iconSize column on ConversionJob, app.js/worker.js wiring, and the
frontend size picker. Every code snippet (icojs encode/decode, the
heic-convert ESM import, prisma db execute/migrate status flags) was
verified against the actual installed/resolved packages rather than
guessed.
2026-07-31 09:54:06 +02:00
anthony fc217d8aae Add HEIC/HEIF test fixtures for upcoming heic-convert-based decoding
Reuses libheif's own LGPL/MIT-licensed with-alpha-512x512.heic sample
under both a .heic and .heif filename, verified to decode correctly
via heic-convert (the library the image format work will use). No
suitably-licensed HEVC/mif1-branded .heif-distinct sample exists that
is compatible with the pinned libheif-js version, and file-type detects
both extensions identically regardless of container brand, so the
duplicate content is sufficient to exercise the heif source-format
code path.
2026-07-31 09:48:11 +02:00
anthony 587ace3366 package.json > create deploy script 2026-07-31 09:31:13 +02:00
anthony bac93c853a Add design spec for HEIC/HEIF (source-only) and ICO image formats
Drops HDR from scope: the installed sharp/libvips build has it fully
disabled and no viable library exists for either direction.
2026-07-31 09:30:26 +02:00
anthony b40a7d340f Add support for csv + xlsx 2026-07-31 09:17:08 +02:00
anthony 4c408d83e9 Markdown conversion doc + CLAUDE.md improve 2026-07-31 08:40:04 +02:00
anthonyandClaude Sonnet 5 756e875fd9 feat: add md<->txt passthrough document converters
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 08:34:51 +02:00
anthonyandClaude Sonnet 5 70c0c5ce6b feat: add md<->docx document converters
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 08:33:31 +02:00
anthonyandClaude Sonnet 5 82533ca436 feat: add md<->pdf document converters
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 08:31:53 +02:00
anthonyandClaude Sonnet 5 1595c5e0af feat: add md<->html document converters
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 08:31:00 +02:00
anthonyandClaude Sonnet 5 28b6edac82 feat: add MIME plumbing for markdown (.md) format
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-31 08:29:55 +02:00
anthony 7d61209bd8 CLAUDE.md > add precisions for o2switch that need precompiled binaries 2026-07-31 08:28:14 +02:00
anthony 02ae3bc44b docs: add design spec for Markdown (.md) document conversion
Adds md<->html, md<->txt, md<->docx, md<->pdf via markdown-it and turndown.
2026-07-31 08:20:29 +02:00