Commit Graph
442 Commits
Author SHA1 Message Date
Amruth Pillai 00b8e3ebf5 feat: add Cloudflare Workers deployment support 2026-10-02 14:05:37 +02:00
Amruth Pillai 99ff19e4e8 feat(templates): add Porygon and Smeargle templates
Porygon lays the resume out as a ruled form after the Japanese résumé
form (rirekisho). The header is a block of bordered field cells framed
in the accent color with the photo in a cell of its own, and every
section is a table with a solid title bar over one ruled cell per
entry. Touching cells share one tinted rule.

Smeargle sets the resume like a magazine feature: the headline as an
uppercase kicker over a display name, the summary as an italic
standfirst, and italic section headings at the user's heading size.

Both are one-column and ATS-safe. Register them in the schema, renderer,
semantic manifests and gallery, add gallery and docs previews, extract
the new descriptions, regenerate the API spec, and list them wherever
the docs enumerate templates.
2026-10-02 01:18:59 +02:00
Amruth Pillai 78f4f81831 fix(mcp): complete API parity and harden authentication and transport 2026-10-02 00:16:34 +02:00
Amruth Pillai 57171c6fcb feat(api): add REST endpoints for imports, exports, checks and pagination
Resource-oriented REST aliases cover file imports (PDF text layer, JSON
Resume, Reactive Resume v4/current, LinkedIn), PDF/DOCX/Markdown/JSON
exports for resumes and cover letters, editor content checks, job-term
matching and a public PDF readability checker. Collection endpoints accept
limit/offset with X-Total-Count headers, and PATCH routes cover partial
updates. Existing routes and response shapes stay unchanged.

The OpenAPI spec marks public operations with `security: []`, the REST
surface gets a 40 MiB body limit, and Better Auth publishes its own
OpenAPI schema. Cookie sessions are rejected for cross-origin requests.
DOCX export parses HTML with node-html-parser so it runs on the server,
and PDF line extraction moves to @reactive-resume/import for reuse.
2026-10-01 23:01:11 +02:00
Amruth Pillai 8320f9ea27 docs(changelog): embed the v6 video 2026-10-01 23:00:53 +02:00
Amruth Pillai 1459259dd0 docs: update v6 changelog with latest changes 2026-10-01 07:46:37 +02:00
Amruth Pillai bc92b8cf7f fix: finalize v6 migrations and document workflows 2026-10-01 07:06:15 +02:00
Amruth Pillai fcfb18fe5a chore: migrate linting and formatting to Oxc 2026-09-30 22:53:16 +02:00
Amruth Pillai 3e7849e51f feat: save jobs and prepare applications
Keep manual preparation available without provider credentials.
Share bounded search and reading across Applications and the assistant
with one selected Firecrawl, Tavily, or Exa connection.

Backfill encrypted Firecrawl credentials without decrypting or removing
legacy rows. Add nullable posting-source metadata to applications.
2026-09-30 22:43:45 +02:00
Amruth Pillai 0bdf8066cd fix: make monorepo checks and caching consistent 2026-09-30 22:32:05 +02:00
Amruth Pillai bec152b7e9 feat: add shared AI and Firecrawl job search integrations
Add managed credentials, job posting search and scraping, database migration, translations, and self-hosting documentation. Fix empty resume-copy recovery and ensure every sheet popup renders inside a drawer viewport.
2026-09-30 21:00:43 +02:00
Amruth Pillai e67b1c7ae9 docs(changelog): update title and description for clarity 2026-09-30 07:22:09 +02:00
Amruth Pillai b87b31f7e9 docs(changelog): add release notes for v6.0.0 with breaking changes and new features 2026-09-30 07:12:21 +02:00
Amruth Pillai 9a803305c8 fix: address verified v6 app findings
Fix authentication recovery, account imports, application tracking, resume
editing and exports, sharing, API contracts, provider selection, and private
local attachments. Preserve authored content during PDF pagination.

Update guides, generated OpenAPI output, and translation catalogs to match
verified behavior and documented constraints.

Validation: 1,019 tests passed; 12 database/OAuth integration tests skipped.
Ten affected package typechecks, production build, Biome, and package
boundaries passed.
2026-09-30 06:15:09 +02:00
Amruth Pillai d46b4b5815 docs: rewrite the documentation for v6
Rewrite every guide for the redesigned app, add guides for new features (documents, editor modes, check, cover letters, assistant, applications, self-hosting upgrade and environment reference), remove v5-only pages with redirects, and replace every screenshot.
2026-09-30 05:07:06 +02:00
Amruth Pillai 883045b14c fix(tooling): mark generated doc blocks with mdx comments
Mintlify's MDX parser rejects HTML comments, so the JSON schema guide failed mint validate.
2026-09-30 05:07:05 +02:00
Amruth Pillai 6d4ceefbdf fix(pdf): honor soft hyphens for every hyphenated language
Forme hyphenates every language it has patterns for, so drop the German-only
gate on soft-hyphen decoding and the "Currently supports German" schema note.
2026-09-30 01:07:33 +02:00
Amruth Pillai 725be158c0 feat(deploy): deploy Vercel as frontend and backend services
Vercel now deploys Reactive Resume as two services in one project:
`frontend` serves the static Vite build from apps/web/dist, and
`backend` runs the Hono server Function from apps/server. Top-level
rewrites send server-owned paths (/api, /uploads, /mcp, /.well-known,
robots.txt, sitemap.xml, llms.txt, schema.json, index.html) and every
path without a file extension to `backend`, so HTML shells keep their
injected SEO metadata. Paths with a file extension go to `frontend`.

The service builder needs a few accommodations:

- apps/server/vercel.mjs replaces api/index.mjs as the entrypoint,
  because a service entrypoint must exist before the build runs.
- `outputDirectory: "."` stops the builder from using the Docker
  entrypoint in dist/ as the Function handler.
- The builder loads external CommonJS dependencies through pnpm links
  that it leaves out of the Function. ioredis and react-reconciler are
  now bundled with their dependencies, and bcrypt is replaced with
  bcryptjs, which reads and writes the same $2b$ hashes.

The Vercel compatibility workflow now builds with the services
framework and loads a copy of the backend Function outside the
checkout, so a dependency missing from the Function fails CI. The stale
PDFKit trace checks are removed.

Existing Vercel installations must set Framework Preset to Services
before redeploying; the self-hosting guide documents this.
2026-09-30 00:17:24 +02:00
Amruth Pillai 01e87a6f1b feat(web): show resume details in the document menu and ask for donations after a download
The document menu's Information item opened a donation appeal and a row of
project links, which isn't what anyone expects from a resume's menu. It's now
Details: when the resume was created and last edited, its template, language
and page count, and whether it's private or shared (with its link). The
resume API returns `createdAt` for this.

The donation ask moves to the moment someone has what they came for: after a
successful download in Share & export (resumes and cover letters), one quiet
line wishes them luck and links to Open Collective. The old dialog's links
(docs, source, translations, bug reports, donate) live in the Settings
sidebar footer.
2026-09-29 23:24:15 +02:00
Amruth Pillai 394e59e1af refactor(resume): drop semantic css features without a clear pdf meaning
Remove the revert and unset keywords, vw/vh units, the |= and $= attribute
matchers, :nth-child(... of ...), the stylesheet analyzer and the
engine-unsupported warnings. inherit and initial remain the CSS-wide keywords.
2026-09-29 18:50:00 +02:00
Amruth Pillai 92459122c5 feat(server): convert legacy style rules with a manual script instead of at startup
The conversion of stored legacy style rules to Semantic CSS no longer runs
when the server starts. The image now ships
apps/server/dist/migrate-legacy-styles.mjs, run by hand against
DATABASE_URL:

- without flags it's a dry run that converts in memory and reports counts
- --apply --backup <file> converts, appending every replaced stylesheet to
  the backup file before its row is written
- --restore <file> puts those stylesheets back, except on rows edited since

Each table is scanned once for the rows that need converting, then they're
converted in batches with progress logged. Only metadata.stylesheet is
rewritten, a row whose stylesheet changed after it was read is left alone,
and running it again skips what's converted. The data_migration table that
recorded the startup run is gone. The self-hosting guide explains the
one-time run.
2026-09-29 16:57:21 +02:00
Amruth Pillai cfb272229b feat(web): pick an element on the page to style it in custom styles
With Custom Styles open, clicking a section or entry on the page adds a
rule for it under a comment naming it (or moves the cursor into its
existing rule). While the cursor is in a rule, everything it matches is
outlined on the page. Autocomplete offers sections and entries by name
and inserts their selector, instead of escaped UUIDs. The guide gains a
Style one element section, including the :nth-of-type form.
2026-09-29 14:53:23 +02:00
Amruth Pillai 31fb576099 feat(web): write custom styles as plain CSS without a version line or checker
Custom styles no longer need @version 1; at the top: the language
version already lives beside the text, so new and converted stylesheets
leave it out, the editor hides it in older ones, and the compiler
ignores it. The validity status and inline diagnostics are gone too:
whatever applies shows in the preview and anything else is left out.
2026-09-29 14:31:59 +02:00
Amruth Pillai 2506509538 feat: make cover letters documents of their own
Resumes no longer hold cover-letter sections. A migration saves every
letter a resume carried as a letter linked to that resume's details and
design, hands a resume's only letter to its only letter-less application,
then removes the sections from resumes and their layouts. rollback.sql
puts them back.

Every resume write on the server moves any letter it still carries into
a saved letter in the same transaction, so stale tabs, older files, API
clients and restored versions keep working without duplicating letters.

The resume editor no longer adds or imports letters, the resume download
drops its Cover letter tab, and resume PDF downloads (API, signed links,
MCP) no longer take a cover-letter target. copy_embedded_cover_letter and
POST /cover-letters/from-resume are removed.
2026-09-29 09:30:07 +02:00
Amruth Pillai cbc76b03b1 refactor!: contract the redesign's legacy fields
The expand steps of the redesign kept older app versions and API clients
working. This removes those compatibility paths:

- Entry date text (period/date) is written from the structured dates on
  every save; an edit to the text alone is overwritten.
- application.archived is dropped; archived rows close first. CSV import
  still reads the flag from older exports.
- resume_version.label is dropped; versions are named by kind and name.
- rejected is no longer accepted as a stage; remaining rows and history
  close first. CSV import still maps it to closed.

BREAKING CHANGE: older app versions and API clients that read or write
archived, version labels, the rejected stage or date text alone no
longer work. migrations/20260929063245_contract_redesign_legacy_fields
has a rollback.sql that restores the dropped columns.
2026-09-29 08:34:27 +02:00
Amruth Pillai 49422e98f2 feat: give a letter its own type, colors and page 2026-09-29 08:14:37 +02:00
Amruth Pillai 098df60230 feat: choose which side the sidebar sits on
Two-column templates take a sidebarSide from the layout (left or right).
Without one, each template keeps its own side and right-to-left pages
mirror it. The PDF templates reverse only their columns, header band
and sidebar background, and the DOCX export follows the same choice.
Design's Sidebar panel offers Left and Right.
2026-09-29 08:00:33 +02:00
Amruth Pillai c0bf1aebaf feat(pdf): remove react-pdf and move every consumer to forme
The web preview, downloads, template gallery, server export and public
PDF render through Forme. react-pdf, react-pdf-html, the react-pdf
hyphenation package, the Phosphor react-pdf icons and the four patches
are gone. Hyphenation now follows the page language for every language
Forme has patterns for.

Semantic CSS keeps its language; declarations Forme can't draw raise an
ENGINE_UNSUPPORTED warning in the editor. The page map rebuilds blocks
Forme leaves out of its layout when they break across pages, and a
render that misplaces a box is repeated with nested rows kept whole.

Tests move to a small shim with the react-pdf calls they were written
against; tests of react-pdf internals are dropped. Forme limits are
recorded as expected failures (RTL line order, characters above
U+FFFF).
2026-09-29 07:11:40 +02:00
Amruth Pillai 991d7e0c32 docs: describe the new ATS checker and its fix flow 2026-09-29 00:50:21 +02:00
Amruth Pillai a043b28867 docs: point the guides at the new settings pages
Guides now name Account, Preferences and AI & developer, the new key flow, and what the account export contains.
2026-09-29 00:33:44 +02:00
Amruth Pillai 26044b5346 docs: regenerate the OpenAPI spec and JSON schema guide
The published spec had fallen behind the runtime routes, including the cover-letter draft and version routes, and the schema guide was missing Check metadata. The OpenAPI test now lists the new letter routes and the Trash wording.
2026-09-29 00:11:06 +02:00
Amruth Pillai bda01febd5 feat(schema): structured resume dates with a read-time upgrade and dual write
Dated entries and roles carry dates (start, end, present, and raw when the
text couldn't be read exactly). The parser moves to the schema package and
reports how each date was written; parseResumeData fills dates, infers the
date format from how dates were typed and rewrites the legacy period/date
text from them, so older clients and API readers keep working. API writes
sync against the stored data, so an edit to the text alone is read back
into dates.

getById and getBySlug return upgraded data, ATS date rules and sorting read
dates, JSON Resume and LinkedIn imports map their dates directly, entry
titles may be empty (drafts aren't printed), and the MCP schema resource is
generated live in place of the stale schema.json.
2026-09-28 18:20:18 +02:00
Amruth Pillai a7f1829484 ci: default to GitHub-hosted runners with opt-in Blacksmith
Workflows now run on GitHub-hosted runners unless the repository
variable USE_BLACKSMITH is "true", so forks work without setup. When
enabled, jobs run on Blacksmith runners (32 vCPU for build/test, 2 vCPU
for lightweight jobs) and use useblacksmith/checkout,
useblacksmith/setup-docker-builder, and useblacksmith/build-push-action.
Docker layer caches are keyed per architecture.

Replaces the CI_RUNNER_X64 and CI_RUNNER_ARM64 variables.
2026-09-28 09:01:00 +02:00
FalconSpyClaude Opus 5.5Amruth Pillaiautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1b78e546e2 feat(applications): schedule interviews and view them on a calendar (#3539)
* feat(applications): schedule interviews and view them on a calendar

Interviews (screening, technical, behavioral, onsite, other) are stored as
"interview" entries on an application's activity timeline, so an application
can have any number of them and they show in its timeline without a
migration. Each interview has a start date-time (timezone-aware), duration,
and optional location and notes.

- schema: interview timeline entry type, interviewDetailsSchema, INTERVIEW_KINDS
- api: addInterview / updateInterview procedures (delete via timeline entry);
  generic timeline updates now only edit text on note entries
- web: Calendar view on the Applications page (month grid, type legend,
  upcoming list grouped by day, schedule button with application picker,
  per-day "+" and "+N more" popover), Interviews section and interview
  dialog in the application detail panel, interview rows in the timeline
  and CSV export
- mcp: add_application_interview / update_application_interview tools
- i18n: extract new strings into all locale catalogs (English fallback)
- docs: MCP tool table, scheduling guide section, resume-builder skill

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(applications): keep interview dates in local time and guard generic timeline edits

- Format the timeline date chip for interview entries in the viewer's local
  timezone so it matches the interview's date-time label; stage and note
  entries still render in UTC.
- Reject interview entries in the generic updateTimelineEntry path. A
  day-granular date edit kept the UTC time of day and could move an interview
  to the wrong local day; callers are pointed to updateInterview
  (update_application_interview). The MCP tool description now says so, and
  a service test covers the rejection.
- Associate each interview dialog label with its control via useId/htmlFor.
- Drop the duplicate onInput handler on the date-time input; onChange covers
  controlled inputs.
- Give the calendar's per-day schedule button an accessible name that
  includes the date, and update the extracted locale catalogs for the new
  message.

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-09-28 08:57:25 +02:00
Lihan YANGAmruth Pillaiautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
73e7a3cb6d fix(dev): make dotenvx available through pnpm (#3537)
* fix(dev): make dotenvx available through pnpm

* fix(dev): load local env from root scripts

* [autofix.ci] apply automated fixes

---------

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-09-28 08:57:14 +02:00
Amruth Pillai 0cb83602f5 fix(docker): create SeaweedFS bucket with aws-cli instead of minio/mc (#3544)
quay.io/minio/mc:latest is no longer publicly pullable (401 UNAUTHORIZED),
which broke the Docker publish workflow. Use the official amazon/aws-cli
image to create the bucket idempotently via head-bucket || s3 mb.
2026-09-26 10:25:04 +02:00
Amruth Pillai 712298843b chore(release): v5.3.2 (#3542) 2026-09-26 02:55:57 +02:00
Amruth Pillai 8c40313980 feat(deploy): support Vercel Hobby alongside Docker (#3541)
* feat(deploy): support Vercel Hobby alongside Docker

* fix(deploy): include PDFKit runtime font assets

* docs(deploy): document Vercel and Docker setup

* docs(deploy): record storage persistence checks

* refactor(deploy): drop scheduled staging cleanup

Staging uploads are deleted after finalization and expired ones are swept
on each new upload, so the Vercel cron job, its route, and CRON_SECRET are
no longer needed. The Deploy with Vercel wizard now asks for two secrets.

* docs(deploy): restructure Vercel guides

Split the Vercel page into a how-to with its environment reference, move the
large RPC staging protocol to an API reference page, and move CI deployment
checks to the contributing section. Point Deploy with Vercel buttons at main.

* chore: remove agent planning records and fix web app description

Delete superpowers plans/specs, ADRs, issue plans, execution briefs, domain
context maps, and Europass research. Describe apps/web as a TanStack Router
SPA served by apps/server.

* refactor(deploy): simplify Vercel support code

- Share one Redis client and key namespace through @reactive-resume/db/redis
  for API and auth instead of a second auth-only client.
- Drop the auth seeding retry; the provider already treats concurrent inserts
  as no-ops and deployment preparation seeds before runtime.
- Detect staging support from POST /api/storage/stage (404 on Docker) instead
  of a separate GET probe.
- Read staged bodies directly; the signed upload already caps their size.
- Close per-subscription Redis connections with disconnect() alone.
- Check Blob health with one list call instead of write/read/delete.
- Remove redundant tsdown onlyBundle list, dead namespace fallbacks, and the
  conditional spread in the health status.

* fix(deploy): heal stopped runs with dead owners and keep auth up without Redis

- Run owners refresh a Redis heartbeat until they release their claim. Stop
  requests reap the run immediately when the owner has stopped heartbeating,
  instead of leaving the thread blocked until the 15-minute TTL reaper.
- Auth and oRPC rate limiters fall back to per-instance memory limits when
  Redis errors, instead of rejecting every login or failing requests.

* ci: allow esbuild build for Vercel CLI and register deployment deps with knip

pnpm 12 fails dlx installs with ignored build scripts, so allow esbuild
explicitly. The server bundle keeps @vercel/blob, ioredis, and jose external,
and api/index.mjs is the Vercel Function entry.

* fix(web): send buffered RPC bodies instead of teed streams

Reading a request clone turned the original body into a stream, which
browsers send without inspectable request data and which needs duplex
mode. Send the already buffered Blob for direct requests.

* fix(web): send direct RPC bodies as bytes

Blob request bodies are sent as data pipes, so browser tooling cannot
inspect them. Buffer the original request as an ArrayBuffer and send those
bytes; this restores the e2e save assertions that match on request data.
2026-09-26 02:37:22 +02:00
Lihan YANGandAmruth Pillai f0bc26cb3d fix(ci): restore Docker publishing with portable runner fallbacks (#3533)
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-09-22 17:07:28 +02:00
Amruth Pillai 582a6fb429 fix(web): preserve dialogs opened during close animations
Opening another dialog during the previous dialog's 300 ms close animation could clear the new dialog and its close handler. This caused the post-merge dashboard lifecycle test to lose the Duplicate Resume dialog after renaming a resume.

- Scope delayed cleanup to the original dialog and require it to remain closed.
- Add regression coverage for both open and closing replacement dialogs; both cases failed before the fix and pass afterward.
- Include the fix in the v5.3.1 release notes.

Validation: `pnpm check`, `pnpm typecheck`, `pnpm test`, and the focused dialog-store suite (12 passing tests).
2026-09-17 12:19:06 +02:00
Amruth Pillai 24d9e5fb5c chore: release v5.3.1
Prepare v5.3.1 with dashboard search and thumbnail improvements, PDF layout fixes, cover-letter integrations, and self-hosting updates.

- Bump the root version and add release notes with contributor credits, cover-letter REST migration instructions, and the new GHCR image path.
- Align the dashboard authentication plugin with Better Auth's fetch dependency to restore auth-client type inference.
- Regenerate the OpenAPI specification so published validation limits match runtime schemas.

Validation: `pnpm lingui:extract` (no missing translations), `pnpm check`, `pnpm typecheck`, and `pnpm test`.
2026-09-17 12:02:03 +02:00
Emanuele TonelloandAmruth Pillai fbf1f8fbac docs(api): describe cover letter endpoints (#3509)
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-09-17 00:13:21 +02:00
Emanuele TonelloandAmruth Pillai e6a6bf0e6a feat(mcp): add independent cover-letter tools (#3508)
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-09-16 22:08:23 +02:00
PerryLinkandAmruth Pillai 3c5908819c docs(self-hosting): add Kubernetes self-hosting guide (#3515)
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-09-16 18:03:44 +02:00
Amruth Pillai fd3494ccac docs: confirm repository migration and current-version redeployment 2026-09-12 11:29:04 +02:00
Amruth Pillai f89acb4368 chore: migrate repository links to reactive-resume/reactive-resume 2026-09-12 11:18:32 +02:00
Amruth Pillai e3717251cb docs: switch to verified public GHCR images 2026-09-11 11:21:49 +02:00
Amruth Pillai 30b21fa1e3 ci: verify anonymous container pulls before deployment 2026-09-11 11:17:10 +02:00
Amruth Pillai d77cb93494 fix: complete repository links and container publishing migration 2026-09-11 11:09:55 +02:00
Amruth Pillai 9550910f17 revert: remove repository migration changes from main 2026-09-11 03:23:27 +02:00