# Archive agent thread Source: https://docs.rxresu.me/api-reference/agent/archive-agent-thread /spec.json post /agent/threads/{id}/archive # Create agent attachment Source: https://docs.rxresu.me/api-reference/agent/create-agent-attachment /spec.json post /agent/attachments # Create agent thread Source: https://docs.rxresu.me/api-reference/agent/create-agent-thread /spec.json post /agent/threads # Delete agent attachment Source: https://docs.rxresu.me/api-reference/agent/delete-agent-attachment /spec.json delete /agent/attachments/{id} # Delete agent thread Source: https://docs.rxresu.me/api-reference/agent/delete-agent-thread /spec.json delete /agent/threads/{id} # Get agent thread Source: https://docs.rxresu.me/api-reference/agent/get-agent-thread /spec.json get /agent/threads/{id} # Get or create an in-resume agent thread Source: https://docs.rxresu.me/api-reference/agent/get-or-create-an-in-resume-agent-thread /spec.json post /agent/threads/for-resume # List agent threads Source: https://docs.rxresu.me/api-reference/agent/list-agent-threads /spec.json get /agent/threads # Restore agent action snapshot Source: https://docs.rxresu.me/api-reference/agent/restore-agent-action-snapshot /spec.json post /agent/actions/{id}/revert # Resume agent message stream Source: https://docs.rxresu.me/api-reference/agent/resume-agent-message-stream /spec.json get /agent/messages/resume # Send agent message Source: https://docs.rxresu.me/api-reference/agent/send-agent-message /spec.json post /agent/messages/send # Stop active agent run Source: https://docs.rxresu.me/api-reference/agent/stop-active-agent-run /spec.json post /agent/messages/stop # Update agent thread settings Source: https://docs.rxresu.me/api-reference/agent/update-agent-thread-settings /spec.json patch /agent/threads/{id} # Create saved AI provider Source: https://docs.rxresu.me/api-reference/ai-providers/create-saved-ai-provider /spec.json post /ai-providers Stores an encrypted provider/model/API key combination. The key is never returned. # Delete saved AI provider Source: https://docs.rxresu.me/api-reference/ai-providers/delete-saved-ai-provider /spec.json delete /ai-providers/{id} Deletes a saved provider/model/API key combination. # List saved AI providers Source: https://docs.rxresu.me/api-reference/ai-providers/list-saved-ai-providers /spec.json get /ai-providers Lists saved provider/model/API key combinations for the authenticated user. API keys are redacted. # Test saved AI provider Source: https://docs.rxresu.me/api-reference/ai-providers/test-saved-ai-provider /spec.json post /ai-providers/{id}/test Decrypts the saved API key server-side and validates the provider/model connection. # Update saved AI provider Source: https://docs.rxresu.me/api-reference/ai-providers/update-saved-ai-provider /spec.json patch /ai-providers/{id} Updates a saved provider/model/API key combination. Updating the key requires retesting before use. # Chat with AI to modify resume Source: https://docs.rxresu.me/api-reference/ai/chat-with-ai-to-modify-resume /spec.json post /ai/chat Streams a chat response from the configured AI provider. The LLM can call the propose_resume_patches tool to generate JSON Patch proposals for explicit user approval. Requires authentication and AI provider credentials. # Parse a DOCX file into resume data Source: https://docs.rxresu.me/api-reference/ai/parse-a-docx-file-into-resume-data /spec.json post /ai/parse-docx Extracts structured resume data from a DOCX or DOC file using the specified AI provider. The file should be sent as a base64-encoded string along with AI provider credentials and the document's media type. Returns a complete ResumeData object. Requires authentication. # Parse a PDF file into resume data Source: https://docs.rxresu.me/api-reference/ai/parse-a-pdf-file-into-resume-data /spec.json post /ai/parse-pdf Extracts structured resume data from a PDF file using the specified AI provider. The file should be sent as a base64-encoded string along with AI provider credentials. Returns a complete ResumeData object. Requires authentication. # Review extracted resume text Source: https://docs.rxresu.me/api-reference/ai/review-extracted-resume-text /spec.json post /ai/ats-review Reviews the plain text extracted from a resume PDF and returns qualitative feedback: a summary, rewrite suggestions, strengths, and — when a job description is supplied — how the candidate's experience lines up with the role. Deliberately returns no score: the deterministic ATS report owns the only number in this feature. Requires authentication and AI credentials. # Application pipeline stats Source: https://docs.rxresu.me/api-reference/applications/application-pipeline-stats /spec.json get /applications/stats Returns aggregate counts (per stage, per source) for the Insights view. Requires authentication. # Attach an application document Source: https://docs.rxresu.me/api-reference/applications/attach-an-application-document /spec.json post /applications/{id}/documents/{kind} Uploads and attaches a PDF document to an application. Kind must be either resume or cover-letter. Requires authentication. # Bulk delete applications Source: https://docs.rxresu.me/api-reference/applications/bulk-delete-applications /spec.json post /applications/bulk-delete Permanently deletes multiple applications at once. Requires authentication. # Bulk import applications Source: https://docs.rxresu.me/api-reference/applications/bulk-import-applications /spec.json post /applications/import Creates many applications at once from a parsed CSV. Each item requires company and role. Returns the number imported. Requires authentication. # Bulk update applications Source: https://docs.rxresu.me/api-reference/applications/bulk-update-applications /spec.json post /applications/bulk-update Applies the same change (move stage, archive/unarchive, add tags) to multiple applications at once. Requires authentication. # Create a job application Source: https://docs.rxresu.me/api-reference/applications/create-a-job-application /spec.json post /applications Creates a new job application in the pipeline. Company and role are required; all other fields (stage, location, salary, source, linked resume, follow-up, notes, contacts) are optional. Requires authentication. # Delete a job application Source: https://docs.rxresu.me/api-reference/applications/delete-a-job-application /spec.json delete /applications/{id} Permanently deletes a job application. Requires authentication. # Delete a timeline entry Source: https://docs.rxresu.me/api-reference/applications/delete-a-timeline-entry /spec.json delete /applications/{id}/timeline/{entryId} Deletes a note or older stage entry. The current stage entry cannot be deleted. Requires authentication. # Get application by ID Source: https://docs.rxresu.me/api-reference/applications/get-application-by-id /spec.json get /applications/{id} Returns a single job application with its full detail (contacts, activity timeline, linked resume). Only applications belonging to the authenticated user can be retrieved. Requires authentication. # List application tags Source: https://docs.rxresu.me/api-reference/applications/list-application-tags /spec.json get /applications/tags Returns the distinct tags used across the user's applications. Requires authentication. # List job applications Source: https://docs.rxresu.me/api-reference/applications/list-job-applications /spec.json get /applications Returns all job applications belonging to the authenticated user, most recently updated first. Archived applications are excluded unless includeArchived is set. Optionally filter by pipeline stage. Requires authentication. # Log a note on the timeline Source: https://docs.rxresu.me/api-reference/applications/log-a-note-on-the-timeline /spec.json post /applications/{id}/notes Appends a free-text note to the application's activity timeline. Requires authentication. # Post applications aidraft message Source: https://docs.rxresu.me/api-reference/applications/post-applications-aidraft-message /spec.json post /applications/{id}/ai/draft-message # Post applications aimatch score Source: https://docs.rxresu.me/api-reference/applications/post-applications-aimatch-score /spec.json post /applications/{id}/ai/match-score # Post applications aitailor resume Source: https://docs.rxresu.me/api-reference/applications/post-applications-aitailor-resume /spec.json post /applications/{id}/ai/tailor-resume # Post applicationsaiautofill Source: https://docs.rxresu.me/api-reference/applications/post-applicationsaiautofill /spec.json post /applications/ai/autofill # Remove an application document Source: https://docs.rxresu.me/api-reference/applications/remove-an-application-document /spec.json delete /applications/{id}/documents/{kind} Removes a resume or cover-letter PDF from an application and clears the stored document fields. Requires authentication. # Update a job application Source: https://docs.rxresu.me/api-reference/applications/update-a-job-application /spec.json put /applications/{id} Updates one or more fields of an application, including moving it to a different pipeline stage or archiving it. Moving stages automatically appends an entry to the activity timeline. Only provided fields are changed. Requires authentication. # Update a timeline entry Source: https://docs.rxresu.me/api-reference/applications/update-a-timeline-entry /spec.json put /applications/{id}/timeline/{entryId} Updates a timeline entry date, or note text for note entries. Requires authentication. # Delete user account Source: https://docs.rxresu.me/api-reference/authentication/delete-user-account /spec.json delete /auth/account Permanently deletes the authenticated user's account, including all resumes, uploaded files (profile pictures, screenshots, PDFs), and associated data. This action is irreversible. Requires authentication. # Export user account data Source: https://docs.rxresu.me/api-reference/authentication/export-user-account-data /spec.json get /auth/account/export Returns a JSON-serializable export of the authenticated user's data, including their public profile fields, resumes, and independent cover letters. Images remain URL references. Secrets such as password hashes, tokens, and API keys are never included. Requires authentication. # List authentication providers Source: https://docs.rxresu.me/api-reference/authentication/list-authentication-providers /spec.json get /auth/providers Returns a list of all authentication providers enabled on this Reactive Resume instance, along with their display names. Possible providers include password-based credentials, Google, GitHub, LinkedIn, and custom OAuth. No authentication required. # Get feature flags Source: https://docs.rxresu.me/api-reference/feature-flags/get-feature-flags /spec.json get /flags Returns the current feature flags for this Reactive Resume instance. Feature flags control instance-wide settings such as whether new user signups or email-based authentication are disabled. No authentication required. # Get GitHub star count Source: https://docs.rxresu.me/api-reference/platform-statistics/get-github-star-count /spec.json get /statistics/github/stars Returns the number of GitHub stars for the Reactive Resume repository. The count is cached for up to 6 hours and falls back to a last-known value if the GitHub API is unavailable. No authentication required. # Get total number of resumes Source: https://docs.rxresu.me/api-reference/platform-statistics/get-total-number-of-resumes /spec.json get /statistics/resumes Returns the total number of resumes created on this Reactive Resume instance. The count is cached for up to 6 hours for performance. No authentication required. # Get total number of users Source: https://docs.rxresu.me/api-reference/platform-statistics/get-total-number-of-users /spec.json get /statistics/users Returns the total number of registered users on this Reactive Resume instance. The count is cached for up to 6 hours for performance. No authentication required. # Post coverletterscopyembedded Source: https://docs.rxresu.me/api-reference/post-coverletterscopyembedded /spec.json post /coverLetters/copyEmbedded # Post coverletterscreate Source: https://docs.rxresu.me/api-reference/post-coverletterscreate /spec.json post /coverLetters/create # Post coverlettersdelete Source: https://docs.rxresu.me/api-reference/post-coverlettersdelete /spec.json post /coverLetters/delete # Post coverlettersduplicate Source: https://docs.rxresu.me/api-reference/post-coverlettersduplicate /spec.json post /coverLetters/duplicate # Post coverlettersexport Source: https://docs.rxresu.me/api-reference/post-coverlettersexport /spec.json post /coverLetters/export # Post coverlettersgetbyid Source: https://docs.rxresu.me/api-reference/post-coverlettersgetbyid /spec.json post /coverLetters/getById # Post coverlettersimport Source: https://docs.rxresu.me/api-reference/post-coverlettersimport /spec.json post /coverLetters/import # Post coverletterslist Source: https://docs.rxresu.me/api-reference/post-coverletterslist /spec.json post /coverLetters/list # Post coverlettersrefreshstyle Source: https://docs.rxresu.me/api-reference/post-coverlettersrefreshstyle /spec.json post /coverLetters/refreshStyle # Post coverlettersupdate Source: https://docs.rxresu.me/api-reference/post-coverlettersupdate /spec.json post /coverLetters/update # Get public resume by username and slug Source: https://docs.rxresu.me/api-reference/resume-sharing/get-public-resume-by-username-and-slug /spec.json get /resumes/{username}/{slug} Returns a publicly shared resume identified by the owner's username and the resume's slug. If the resume is password-protected and the viewer has not yet verified the password, a 401 error with code NEED_PASSWORD is returned. No authentication required for public resumes; if authenticated as the owner, private resumes are also accessible. # Remove resume password Source: https://docs.rxresu.me/api-reference/resume-sharing/remove-resume-password /spec.json delete /resumes/{id}/password Removes password protection from a resume. After removal, the resume (if public) can be viewed without entering a password. Requires authentication. # Set resume password Source: https://docs.rxresu.me/api-reference/resume-sharing/set-resume-password /spec.json put /resumes/{id}/password Sets or updates a password on a resume. When a password is set, viewers of the public resume must enter the password before the resume data is revealed. The password must be between 6 and 64 characters. Requires authentication. # Verify resume password Source: https://docs.rxresu.me/api-reference/resume-sharing/verify-resume-password /spec.json post /resumes/{username}/{slug}/password/verify Verifies a password for a password-protected public resume. On success, the viewer is granted access to view the resume data for the duration of their session. No authentication required. # Get resume daily statistics Source: https://docs.rxresu.me/api-reference/resume-statistics/get-resume-daily-statistics /spec.json get /resumes/{id}/statistics/daily Returns a continuous, zero-filled per-day series of view and download counts for the specified resume over the last `days` days (UTC). Requires authentication and resume ownership. # Get resume statistics Source: https://docs.rxresu.me/api-reference/resume-statistics/get-resume-statistics /spec.json get /resumes/{id}/statistics Returns view and download statistics for the specified resume, including total counts and the timestamps of the last view and download. Requires authentication. # Record a public resume PDF download Source: https://docs.rxresu.me/api-reference/resume-statistics/record-a-public-resume-pdf-download /spec.json post /resumes/{username}/{slug}/statistics/download Records a visitor's explicit PDF download after the browser starts saving the file. Requires access to the public resume. For password-protected resumes, first call verifyResumePassword (POST /resumes/{username}/{slug}/password/verify) with the password, then send the returned HttpOnly resume_access_ cookie with this request. A missing or invalid access cookie returns NEED_PASSWORD (HTTP 401); the cookie expires after 10 minutes. Owner downloads are excluded. Rate limited per resume and visitor. # Create a new resume Source: https://docs.rxresu.me/api-reference/resumes/create-a-new-resume /spec.json post /resumes Creates a new resume with the given name, slug, and tags. Optionally initializes the resume with sample data by setting withSampleData to true. The slug must be unique across the user's resumes. Returns the ID of the newly created resume. Requires authentication. # Delete a resume Source: https://docs.rxresu.me/api-reference/resumes/delete-a-resume /spec.json delete /resumes/{id} Permanently deletes a resume and its associated files (screenshots, PDFs) from storage. Locked resumes cannot be deleted; unlock the resume first. Requires authentication. # Download resume as PDF Source: https://docs.rxresu.me/api-reference/resumes/download-resume-as-pdf /spec.json get /resumes/{id}/pdf Generates a PDF for the specified resume and returns it as a forced download. Only resumes belonging to the authenticated user can be downloaded. Requires authentication. # Duplicate a resume Source: https://docs.rxresu.me/api-reference/resumes/duplicate-a-resume /spec.json post /resumes/{id}/duplicate Creates a copy of an existing resume with the same data. Optionally override the name, slug, and tags for the duplicate. If not provided, the original resume's name, slug, and tags are used. Returns the ID of the duplicated resume. Requires authentication. # Get resume by ID Source: https://docs.rxresu.me/api-reference/resumes/get-resume-by-id /spec.json get /resumes/{id} Returns a single resume with its full data, identified by its unique ID. Only resumes belonging to the authenticated user can be retrieved. Requires authentication. # Import a resume Source: https://docs.rxresu.me/api-reference/resumes/import-a-resume /spec.json post /resumes/import Creates a new resume from an existing ResumeData object (e.g. from a previously exported JSON file). A random name and slug are generated automatically. Returns the ID of the imported resume. Requires authentication. # List all resume tags Source: https://docs.rxresu.me/api-reference/resumes/list-all-resume-tags /spec.json get /resumes/tags Returns a sorted list of all unique tags across the authenticated user's resumes. Useful for populating tag filters in the dashboard. Requires authentication. # List all resumes Source: https://docs.rxresu.me/api-reference/resumes/list-all-resumes /spec.json get /resumes Returns a list of all resumes belonging to the authenticated user. Results can be filtered by tags and sorted by last updated date, creation date, or name. Resume data is not included in the response for performance; use the get endpoint to fetch full resume data. Requires authentication. # List resume version history Source: https://docs.rxresu.me/api-reference/resumes/list-resume-version-history /spec.json get /resumes/{resumeId}/versions Returns the recent version-history snapshots for a resume (id, label, and timestamp only). Snapshots are taken at milestones such as imports, AI edits, and periodic manual saves. Only the resume owner can list versions. Requires authentication. # Patch resume data Source: https://docs.rxresu.me/api-reference/resumes/patch-resume-data /spec.json patch /resumes/{id} Applies JSON Patch (RFC 6902) operations to partially update a resume's data. This allows small, targeted changes (e.g. updating a single field) without sending the entire resume object. Locked resumes cannot be patched. Requires authentication. # Restore a resume version Source: https://docs.rxresu.me/api-reference/resumes/restore-a-resume-version /spec.json post /resumes/{resumeId}/versions/{versionId}/restore Non-destructively restores a resume to a previous version snapshot by writing that snapshot's data back through the normal update path. Prior versions are preserved and the restore itself becomes a new snapshot. Only the resume owner can restore versions. Requires authentication. # Set resume lock status Source: https://docs.rxresu.me/api-reference/resumes/set-resume-lock-status /spec.json post /resumes/{id}/lock Toggles the locked status of a resume. When locked, a resume cannot be updated, patched, or deleted. Useful for protecting finalized resumes from accidental edits. Requires authentication. # Subscribe to resume updates Source: https://docs.rxresu.me/api-reference/resumes/subscribe-to-resume-updates /spec.json get /resumes/{id}/updates Streams lightweight invalidation events when the specified resume changes. The event payload contains metadata only; clients should refetch the resume for canonical data. # Update a resume Source: https://docs.rxresu.me/api-reference/resumes/update-a-resume /spec.json put /resumes/{id} Updates one or more fields of a resume identified by its ID. All fields are optional; only provided fields will be updated. Locked resumes cannot be updated. Requires authentication. # Get application health and version Source: https://docs.rxresu.me/api-reference/system/get-application-health-and-version /spec.json get /api/health Checks database and storage availability. Does not require authentication. # Applying Custom Styles Source: https://docs.rxresu.me/applying-custom-styles Use Reactive Resume Semantic CSS to make safe, targeted, and portable changes to your resume PDF. Custom Styles let you make focused changes that are not available in the regular **Design**, **Typography**, **Layout**, **Page**, and **Picture** settings. They use Semantic CSS, a CSS-like language designed for resume PDFs. Semantic CSS styles the PDF output, not the browser interface. It cannot load fonts, images, scripts, or other resources, and it cannot create new resume content. ## Convert existing Custom Styles If a resume still uses the previous Custom Styles form, Reactive Resume creates a converted stylesheet draft. Your current rules remain active while you review it. Open the resume in the builder, select **Design**, then select **Custom Styles**. Check the preview and warnings below the editor. The draft starts with `@version 1;`. Select **Activate Semantic CSS** only after the preview matches the legacy result. Reactive Resume never applies both systems at once, and keeps the original legacy rules available for rollback. ## Make your first change Open the resume you want to style, select **Design**, then select **Custom Styles**. Start with a complete stylesheet: ```css theme={null} @version 1; section[type="experience"] > section-heading { color: #0f766e; text-transform: uppercase; } ``` The first line tells Reactive Resume which language version the stylesheet uses. Keep `@version 1;` at the start of every stylesheet. Add the stylesheet to the editor. Start with one visual change so it is easy to review in the preview. Reactive Resume checks the source in the browser. When the status changes to **Valid**, compare the preview and export if you are ready to share the resume. Add one related change at a time. Your changes use the normal resume autosave and undo history. ## Target the right part of your resume Semantic CSS selectors describe resume content rather than a template's internal HTML. Selector and attribute names are lowercase and case-sensitive. Prefer semantic selectors when you want a style to work across resumes and templates. ### Start with the resume structure | Selector | Targets | Typical use | | ----------------- | ----------------------------------------- | -------------------------------------------------------------------------- | | `resume` | The complete resume | Scope a rule to one template. | | `page` | A rendered PDF page | Set a page size. | | `region` | Header, main, sidebar, or featured region | Style a layout area. | | `header` | The resume header | Style the identity and contact area. | | `section` | A resume section | Target a section type or placement. | | `section-heading` | A section title | Change heading typography or decoration. | | `section-items` | The items in a section | Adjust item layout and gaps. | | `item` | One resume item | Control spacing or pagination for an experience, project, or similar item. | | `item-header` | An item's summary row | Align the title, company, dates, or similar details. | ### Target header and item content | Selector | Targets | Typical use | | ------------------------------ | -------------------------- | --------------------------------------------------- | | `picture` | The profile picture | Change dimensions, crop, border, or picture shadow. | | `name`, `headline` | Header name and headline | Change the main identity typography. | | `contact-list`, `contact-item` | Header contact details | Space or restyle contact details. | | `combined-text` | A template-combined value | Style an item value that combines fields. | | `field` | A named content field | Target a position, company, date, or other field. | | `link` | A structured link | Change linked text or layout. | | `icon`, `level` | An icon or level indicator | Restyle decorative elements. | ### Target rich text and lists | Selector | Targets | | ------------------------------------------------------------------------ | -------------------------------------------------------------------- | | `rich-text`, `rich-heading`, `blockquote`, `paragraph` | Rich-text blocks in descriptions and summaries. | | `list`, `list-item`, `list-marker`, `list-item-content` | Lists, the outer item row, its bullet or number, and its content. | | `strong`, `emphasis`, `underline`, `strike`, `code`, `text-span`, `mark` | Inline rich-text formatting. | | `hard-break`, `horizontal-rule` | A forced line break or horizontal rule. | | `template-part` | A template-provided extension point. Use only with a template guard. | ### Narrow a selector with attributes Use attributes to make a rule specific without relying on a template layout. | Attribute | Use it with | Example | | ----------- | ------------------------------------------------------ | ------------------------------------ | | `type` | `section` | `section[type="experience"]` | | `placement` | `region` and `section` | `region[placement="sidebar"]` | | `region` | `region` | `region[region="sidebar"]` | | `origin` | `section` | `section[origin="main"]` | | `part` | `region`, `section`, `contact-item`, and `item-header` | `region[part~="sidebar-background"]` | | `template` | `resume` | `resume[template="azurill"]` | | `name` | `field` and `template-part` | `field[name="position"]` | | `level` | `rich-heading` | `rich-heading[level="2"]` | | `direction` | `list-item-content` | `list-item-content[direction="rtl"]` | | `id` | Any semantic node when present | `section[id="projects"]` | | `role` | Any semantic node when present | `field[role~="secondary-text"]` | Semantic CSS supports selector lists, descendant (` `), child (`>`), adjacent sibling (`+`), and general sibling (`~`) combinators. It also supports `:root`, `:first-child`, `:last-child`, `:only-child`, `:is()`, `:where()`, `:not()`, `:nth-child()`, and `:nth-of-type()`. ```css theme={null} @version 1; section[type="experience"] > section-heading { border-bottom: 1pt solid #0f766e; } region[placement="sidebar"] { background-color: #f8fafc; padding: 18pt; } section[id="projects"] { break-inside: avoid; } ``` Use an exact `id` only for a resume-specific adjustment. A type, placement, role, or field name is usually a better choice when you expect to copy the stylesheet to another resume. ## Reuse your builder settings Semantic CSS exposes the resolved builder settings as read-only `--resume-*` variables. Define your own variables in `:root`, then reuse the builder values instead of duplicating colors or dimensions. ```css theme={null} @version 1; :root { --accent: var(--resume-primary-color); --rule: #cbd5e1; } section-heading { color: var(--accent); border-bottom: 1pt solid var(--rule); font-size: 11pt; font-weight: 600; letter-spacing: 0.4pt; } ``` Changing the primary color or related setting in the builder updates the corresponding variable automatically. Do not assign a value to a `--resume-*` variable; create an author variable such as `--accent` instead. | Builder setting | Read-only variables | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Colors | `--resume-primary-color`, `--resume-text-color`, `--resume-background-color` | | Typography | `--resume-body-font-size`, `--resume-body-line-height`, `--resume-heading-font-size`, `--resume-heading-line-height` | | Page and layout | `--resume-page-gap-x`, `--resume-page-gap-y`, `--resume-page-margin-x`, `--resume-page-margin-y`, `--resume-page-width`, `--resume-page-height`, `--resume-sidebar-width` | | Picture | `--resume-picture-size`, `--resume-picture-rotation`, `--resume-picture-aspect-ratio`, `--resume-picture-border-radius`, `--resume-picture-border-width`, `--resume-picture-border-color`, `--resume-picture-shadow-width`, `--resume-picture-shadow-color` | Use `pt` for predictable PDF spacing and type sizes. Semantic CSS also accepts `px`, `in`, `mm`, `cm`, `%`, `vw`, `vh`, `em`, and `rem` where the property supports a length. ## Style common resume content The most useful declarations usually fall into a few groups: | Goal | Common declarations | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------- | | Typography | `color`, `font-size`, `font-style`, `font-weight`, `letter-spacing`, `line-height`, `text-align`, `text-decoration`, `text-transform` | | Spacing and layout | `margin`, `padding`, `gap`, `width`, `height`, `display`, `flex`, `flex-direction`, `justify-content`, `align-items`, `order` | | Visual treatment | `background-color`, `border`, `border-radius`, `opacity`, `transform` | | Picture treatment | `object-fit`, `object-position`, `-resume-shadow-color`, `-resume-shadow-width` | | PDF structure | `break-before`, `break-inside`, `orphans`, `widows`, `-resume-min-presence-ahead`, `size` | Use `display: none` only to hide an existing semantic node. Semantic CSS cannot add, remove, duplicate, or re-parent resume data. Semantic CSS keeps background styling PDF-safe. Use a flat color for headers and regions: ```css theme={null} @version 1; header { background-color: #1e293b; } ``` Gradient declarations such as `background-image: linear-gradient(...)` remain unsupported. The editor reports that limitation and suggests `background-color` or another supported property; the unsupported declaration is omitted while neighboring valid declarations remain available for preview and export. ### Style rich-text lists `list-item` is the outer row that holds a marker and its content. Use it for row layout and spacing. Use `list-marker` for the bullet or number, and `list-item-content` for the text flow. ```css theme={null} @version 1; rich-text list-item { gap: 4pt; } list-marker { color: var(--resume-primary-color); } list-item-content { line-height: 1.35; } ``` ### Space level indicators Target `level` to adjust the space between a skill's circles, icons, or other level decorations: ```css theme={null} @version 1; section[type="skills"] level { column-gap: 4pt; } ``` This sets a 4pt horizontal gap between decorations. `gap: 4pt` also works; `gap: 0` removes the gap. `row-gap` does not change horizontal spacing within the single level row. ### Style fields inside an item Named fields let you make a focused change without styling every item value. Use the selector only where that field exists in the selected resume and template. ```css theme={null} @version 1; section[type="experience"] field[name="position"] { font-weight: 600; } section[type="experience"] field[name="company"] { color: var(--resume-primary-color); } ``` ## Use template-specific parts carefully Template parts expose optional visual details that are not shared by every template. Always guard a template-part rule with `resume[template="..."]`; otherwise the selector may match nothing after a template change. ```css theme={null} @version 1; resume[template="azurill"] template-part[name="timeline-line"] { background-color: #94a3b8; } ``` Some template parts are wrappers, while others are attributes on an existing semantic node. Use the matching selector below. | Template | Available selectors | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Azurill | `template-part[name="timeline-content"]`, `template-part[name="timeline-dot"]`, `template-part[name="timeline-line"]`, `template-part[name="timeline-marker"]` | | Bronzor | `section[part~="interleaved-section-row"]` | | Chikorita | `template-part[name="contact-row-primary"]`, `template-part[name="contact-row-secondary"]` | | Ditgar | `template-part[name="featured-summary"]`, `item-header[part~="item-header-border"]`, `region[part~="sidebar-background"]` | | Ditto | `template-part[name="contact-offset"]`, `template-part[name="header-band"]`, `template-part[name="picture-anchor"]` | | Gengar | `template-part[name="featured-summary"]`, `region[part~="sidebar-background"]` | | Glalie | `region[part~="sidebar-background"]` | | Leafish | `template-part[name="header-body"]`, `template-part[name="header-contact-band"]`, `template-part[name="header-intro"]` | | Meowth | `template-part[name="education-grade-row"]`, `template-part[name="inline-item-header-leading"]`, `template-part[name="inline-item-header-middle"]`, `template-part[name="inline-item-header-trailing"]` | | Pikachu | `template-part[name="header-divider"]` | | Rhyhorn | `template-part[name="contact-item-content"]`, `contact-item[part~="contact-item-last"]` | | Scizor | `template-part[name="header-name-rule"]` | Kakuna, Lapras, and Onyx do not expose template-specific parts. Use shared semantic selectors for portable styles. ## Control pagination and PDF dimensions Use structural declarations sparingly and review the exported PDF after each change. You can keep an item together, leave space before a section, or set a custom page size. ```css theme={null} @version 1; page { size: 210mm 297mm; } section { -resume-min-presence-ahead: 72pt; } item { break-inside: avoid; } ``` `size` applies only to `page` and must be outside `@media`. PDF media queries use the authored PDF dimensions, not the browser viewport. ```css theme={null} @version 1; @media (max-width: 600pt) { region[placement="sidebar"] { padding: 12pt; } } ``` Supported media features are `width`, `min-width`, `max-width`, `height`, `min-height`, `max-height`, and `orientation: portrait` or `orientation: landscape`. ## Diagnose and recover safely The editor saves the current source even when it has an error. A recoverable error ignores only the invalid declaration, value, selector, or rule; valid parts still appear in preview and PDF export. A fatal version or resource-limit error ignores the whole stylesheet and renders the resume with its base styles until you fix the source. If a rule does not work: 1. Read the status below the editor. Errors include a line and column number when available. 2. Check the selector's spelling, attribute value, placement, and template guard. A **selector matches nothing** warning usually means the resume does not contain that semantic node. 3. Simplify the rule to one selector and one declaration, then wait for **Valid** before adding more. 4. Use the stylesheet undo and redo controls to restore an earlier source. Select **Open focus mode** when you need a taller editor. On mobile, it opens a full-width sheet; switch to **Preview** to inspect the result. Review the PDF preview before exporting or sharing a resume with Custom Styles. PDF pagination and template-specific details can make a valid stylesheet look different from what you intended. ## Keep styles portable When you copy a stylesheet to another resume, semantic section types, placements, roles, and fields are the safest starting point. Exact IDs and template parts are intentionally specific to a resume or template. 1. Select **Copy stylesheet** in the source resume. 2. Open **Design → Custom Styles** in the destination resume. 3. Paste the stylesheet and review any warnings. 4. Replace or remove exact IDs and template-part rules that do not apply. 5. Wait for **Valid**, then compare the preview and exported PDF. Semantic CSS does not support classes, pseudo-elements, CSS Grid, arbitrary at-rules, `@import`, `@font-face`, `url()`, browser APIs, animations, filters, gradients, general box shadows, or external assets. Use the normal builder settings when you need a font, image, or broader layout change. # Reactive Resume changelog Source: https://docs.rxresu.me/changelog/index Release notes for Reactive Resume covering new features, resume builder updates, PDF export fixes, AI Agent changes, and self-hosting news. ## Highlights * **Manage cover letters in one shared library.** Create, import, search, edit, duplicate, preview, download, and reuse cover letters from the dashboard or resume builder. Letters now keep their own template while still letting you copy sender details and content from a resume. ([#3255](https://github.com/amruthpillai/reactive-resume/issues/3255)) [1d4194a20](https://github.com/amruthpillai/reactive-resume/commit/1d4194a20), [df2e21ef9](https://github.com/amruthpillai/reactive-resume/commit/df2e21ef9), [a3784558b](https://github.com/amruthpillai/reactive-resume/commit/a3784558b) * **MCP connections now use a complete OAuth consent flow.** Dynamic client registration works again, signed authorization requests survive login and two-factor authentication, and a new screen asks users to explicitly Allow or Deny access. ([#3392](https://github.com/amruthpillai/reactive-resume/issues/3392)) [fe9b59e11](https://github.com/amruthpillai/reactive-resume/commit/fe9b59e11) * **Import PDF resumes without configuring an AI provider.** PDFs with readable text are now parsed locally in the browser and turned into an editable resume, while the existing AI-assisted path remains available when a provider is connected. Thanks to [@Syed-Ali-Abbas-Zaidi](https://github.com/Syed-Ali-Abbas-Zaidi). ([#3334](https://github.com/amruthpillai/reactive-resume/issues/3334)) [cce6d64af](https://github.com/amruthpillai/reactive-resume/commit/cce6d64af) * **Do more from the application tracker.** Export the current filtered view to CSV, save contact email and phone details, and turn a generated cover letter into a PDF attachment. Thanks to [@emanuelet](https://github.com/emanuelet). ([#3393](https://github.com/amruthpillai/reactive-resume/issues/3393)) [a3585a24e](https://github.com/amruthpillai/reactive-resume/commit/a3585a24e), [1f0844b39](https://github.com/amruthpillai/reactive-resume/commit/1f0844b39), [bf27792ca](https://github.com/amruthpillai/reactive-resume/commit/bf27792ca) * **Recover and reorganize resume sections more safely.** Restore hidden printable sections, sort dated entries on demand, and choose whether each section heading appears in the exported resume. ([#2725](https://github.com/amruthpillai/reactive-resume/issues/2725), [#3060](https://github.com/amruthpillai/reactive-resume/issues/3060)) [5850230f8](https://github.com/amruthpillai/reactive-resume/commit/5850230f8), [b85d285b6](https://github.com/amruthpillai/reactive-resume/commit/b85d285b6), [368858a56](https://github.com/amruthpillai/reactive-resume/commit/368858a56) * **Choose how profile photos fit.** Cover fills the frame, Contain keeps the whole image visible, and the crop dialog can now upload the original file without cropping. Upload limits are clearer and crop compression is preserved. ([#3305](https://github.com/amruthpillai/reactive-resume/issues/3305)) [ab67831e4](https://github.com/amruthpillai/reactive-resume/commit/ab67831e4), [fa4115072](https://github.com/amruthpillai/reactive-resume/commit/fa4115072), [40c997a39](https://github.com/amruthpillai/reactive-resume/commit/40c997a39) * **Resume previews expose a clearer outline to screen readers.** Entries and nested roles use consistent heading levels, while paragraphs, lists, emphasis, and safe links retain their meaning in the accessible view. [9f0202eac](https://github.com/amruthpillai/reactive-resume/commit/9f0202eac), [acd2a9cfe](https://github.com/amruthpillai/reactive-resume/commit/acd2a9cfe) * **Public sharing is more configurable.** Hide the PDF download button per resume, count successful public downloads correctly, or serve one configured public resume directly from your self-hosted root URL. ([#3360](https://github.com/amruthpillai/reactive-resume/issues/3360), [#3366](https://github.com/amruthpillai/reactive-resume/issues/3366)) [14c7c0651](https://github.com/amruthpillai/reactive-resume/commit/14c7c0651), [cddb01f03](https://github.com/amruthpillai/reactive-resume/commit/cddb01f03), [744eaa902](https://github.com/amruthpillai/reactive-resume/commit/744eaa902) ## Cover Letters & Applications * Added a persistent cover-letter library with ownership-safe saves, revision checks, search, import, duplication, PDF preview and download, resume-content copying, and application attachment snapshots. ([#3255](https://github.com/amruthpillai/reactive-resume/issues/3255)) [1d4194a20](https://github.com/amruthpillai/reactive-resume/commit/1d4194a20) * Separated cover-letter templates from resume-based sender details. Refreshing sender information no longer changes the selected letter template, and the resume builder now links directly to its cover letter. [df2e21ef9](https://github.com/amruthpillai/reactive-resume/commit/df2e21ef9), [a3784558b](https://github.com/amruthpillai/reactive-resume/commit/a3784558b) * Added one-click PDF generation and attachment for Application Copilot cover letters, with retryable progress states. Thanks to [@emanuelet](https://github.com/emanuelet). [bf27792ca](https://github.com/amruthpillai/reactive-resume/commit/bf27792ca) * Added contact email and phone fields to applications. Thanks to [@emanuelet](https://github.com/emanuelet). [1f0844b39](https://github.com/amruthpillai/reactive-resume/commit/1f0844b39) * Added CSV export for the current filtered application list. ([#3393](https://github.com/amruthpillai/reactive-resume/issues/3393)) [a3585a24e](https://github.com/amruthpillai/reactive-resume/commit/a3585a24e) * Fixed saved application notes not appearing in the detail view. ([#3391](https://github.com/amruthpillai/reactive-resume/issues/3391)) [00a1357de](https://github.com/amruthpillai/reactive-resume/commit/00a1357de) * Fixed cover-letter copy failures so errors are reported without leaving stale content behind. Thanks to [@emanuelet](https://github.com/emanuelet). [ef47baf24](https://github.com/amruthpillai/reactive-resume/commit/ef47baf24) * Fixed Application Copilot provider failures returning an internal-server error instead of a useful upstream-provider error. Thanks to [@santhiprakash](https://github.com/santhiprakash). ([#3312](https://github.com/amruthpillai/reactive-resume/issues/3312)) [c4eb9d860](https://github.com/amruthpillai/reactive-resume/commit/c4eb9d860) ## Resume Builder & Editing * Added a Compact resume-library view alongside Grid and List, with the selected view remembered for the browser session. ([#3247](https://github.com/amruthpillai/reactive-resume/issues/3247)) [1f308af72](https://github.com/amruthpillai/reactive-resume/commit/1f308af72) * Added local PDF resume import for users without an AI provider. Scanned PDFs without readable text now receive a clear error instead of entering a blocked import path. Thanks to [@Syed-Ali-Abbas-Zaidi](https://github.com/Syed-Ali-Abbas-Zaidi). ([#3334](https://github.com/amruthpillai/reactive-resume/issues/3334)) [cce6d64af](https://github.com/amruthpillai/reactive-resume/commit/cce6d64af) * Added hidden-section recovery so printable sections missing from the layout can be restored without disturbing authored placement. [5850230f8](https://github.com/amruthpillai/reactive-resume/commit/5850230f8) * Added one-shot ascending or descending date sorting for supported sections. Sorting is explicit and does not keep rearranging later edits. ([#2725](https://github.com/amruthpillai/reactive-resume/issues/2725)) [b85d285b6](https://github.com/amruthpillai/reactive-resume/commit/b85d285b6) * Added per-section heading visibility, allowing repeated or unnecessary headings to be hidden without hiding section content. ([#3060](https://github.com/amruthpillai/reactive-resume/issues/3060)) [368858a56](https://github.com/amruthpillai/reactive-resume/commit/368858a56) * Added Inline and List presentation options for skill keywords, including controlled line breaks for long skill lists. Thanks to [@diego-vega-centeno](https://github.com/diego-vega-centeno). ([#2785](https://github.com/amruthpillai/reactive-resume/issues/2785)) [8df1b2555](https://github.com/amruthpillai/reactive-resume/commit/8df1b2555), [870388192](https://github.com/amruthpillai/reactive-resume/commit/870388192) * Added whole-paragraph indentation and kept authored spaces intact through editing and export. ([#3397](https://github.com/amruthpillai/reactive-resume/issues/3397)) [f468651c7](https://github.com/amruthpillai/reactive-resume/commit/f468651c7), [ea97de5ec](https://github.com/amruthpillai/reactive-resume/commit/ea97de5ec) * Preserved imported tables as editable rich-text tables instead of flattening or losing their structure. [999cd618c](https://github.com/amruthpillai/reactive-resume/commit/999cd618c) * Saved pending resume edits before navigation, preventing the last change from being lost when leaving the builder. [a4bdc54b2](https://github.com/amruthpillai/reactive-resume/commit/a4bdc54b2) * Removed empty custom sections and their now-unused pages after moving the final item elsewhere. ([#3180](https://github.com/amruthpillai/reactive-resume/issues/3180)) [97ccb4ba0](https://github.com/amruthpillai/reactive-resume/commit/97ccb4ba0) * Preserved explicitly entered `http://` links instead of silently rewriting them to HTTPS. ([#2735](https://github.com/amruthpillai/reactive-resume/issues/2735)) [2cbb0f63e](https://github.com/amruthpillai/reactive-resume/commit/2cbb0f63e) * Kept the color picker preview synchronized with the stylesheet source. ([#3291](https://github.com/amruthpillai/reactive-resume/issues/3291)) [735e70092](https://github.com/amruthpillai/reactive-resume/commit/735e70092) * Rendered resume thumbnails at their displayed pixel density for clearer cards without unnecessary work. [2e711fd14](https://github.com/amruthpillai/reactive-resume/commit/2e711fd14) * Added clearer explanations for content that intentionally overflows an authored page and for unsupported CSS gradients. [0fbeeeb4c](https://github.com/amruthpillai/reactive-resume/commit/0fbeeeb4c), [38832014b](https://github.com/amruthpillai/reactive-resume/commit/38832014b) * Hardened rich-text paste handling and removed an unsafe clipboard parsing pattern. [97f34b7cc](https://github.com/amruthpillai/reactive-resume/commit/97f34b7cc) ## PDF Export & Templates * Preserved vertical margins when an item continues onto another page. ([#3337](https://github.com/amruthpillai/reactive-resume/issues/3337)) [bf71253ca](https://github.com/amruthpillai/reactive-resume/commit/bf71253ca) * Kept dates aligned when optional fields are empty, constrained Onyx headlines to page margins, and aligned Ditgar item headers with body text. ([#3338](https://github.com/amruthpillai/reactive-resume/issues/3338), [#3339](https://github.com/amruthpillai/reactive-resume/issues/3339), [#3068](https://github.com/amruthpillai/reactive-resume/issues/3068)) [a2d6bc0c6](https://github.com/amruthpillai/reactive-resume/commit/a2d6bc0c6), [a95e63246](https://github.com/amruthpillai/reactive-resume/commit/a95e63246), [873835a57](https://github.com/amruthpillai/reactive-resume/commit/873835a57) * Added optional German hyphenation to improve line wrapping without changing existing resumes by default. ([#3340](https://github.com/amruthpillai/reactive-resume/issues/3340)) [7d809da6f](https://github.com/amruthpillai/reactive-resume/commit/7d809da6f) * Restored picture borders and soft shadows in PDF output. ([#3017](https://github.com/amruthpillai/reactive-resume/issues/3017)) [57fee67d2](https://github.com/amruthpillai/reactive-resume/commit/57fee67d2) * Fixed skill ratings across templates: grid rows now align, icon opacity reflects the selected level, and Gengar keeps the intended rating order. ([#3343](https://github.com/amruthpillai/reactive-resume/issues/3343), [#3352](https://github.com/amruthpillai/reactive-resume/issues/3352), [#2611](https://github.com/amruthpillai/reactive-resume/issues/2611)) [6d39074c5](https://github.com/amruthpillai/reactive-resume/commit/6d39074c5), [93e8d192a](https://github.com/amruthpillai/reactive-resume/commit/93e8d192a), [2a4a1583b](https://github.com/amruthpillai/reactive-resume/commit/2a4a1583b) * Localized default section headings in server-rendered PDFs, applied semantic heading colors, and stopped the first character of headings from being clipped. Thanks to [@santhiprakash](https://github.com/santhiprakash). ([#2804](https://github.com/amruthpillai/reactive-resume/issues/2804), [#3348](https://github.com/amruthpillai/reactive-resume/issues/3348), [#3380](https://github.com/amruthpillai/reactive-resume/issues/3380)) [b6842fb76](https://github.com/amruthpillai/reactive-resume/commit/b6842fb76), [d53b89ba2](https://github.com/amruthpillai/reactive-resume/commit/d53b89ba2), [e0c2f6d88](https://github.com/amruthpillai/reactive-resume/commit/e0c2f6d88) * Kept unordered-list markers with their first text fragment across page breaks and moved ordered-list markers clear of body text. ([#3344](https://github.com/amruthpillai/reactive-resume/issues/3344)) [ea2beb845](https://github.com/amruthpillai/reactive-resume/commit/ea2beb845), [8d4cf8a2f](https://github.com/amruthpillai/reactive-resume/commit/8d4cf8a2f) * Preserved imported rich-text content even when older data lacks semantic descendants. [aada38088](https://github.com/amruthpillai/reactive-resume/commit/aada38088) * Improved text placement and font handling by honoring requested font metrics, isolating cached glyph metadata, preserving authored Unicode spaces, and retaining glyph positions in RTL previews. [8354c39c4](https://github.com/amruthpillai/reactive-resume/commit/8354c39c4), [d10eb4a55](https://github.com/amruthpillai/reactive-resume/commit/d10eb4a55), [05e48a7cb](https://github.com/amruthpillai/reactive-resume/commit/05e48a7cb), [5c8338c17](https://github.com/amruthpillai/reactive-resume/commit/5c8338c17) * Centered the resume preview correctly in RTL interfaces. ([#2745](https://github.com/amruthpillai/reactive-resume/issues/2745)) [9fdcec2ec](https://github.com/amruthpillai/reactive-resume/commit/9fdcec2ec) * Allowed gaps between level decorations in custom styles. [f629ea1ea](https://github.com/amruthpillai/reactive-resume/commit/f629ea1ea) ## Sharing, Authentication & Accessibility * Added a per-resume setting to hide the public PDF download button. ([#3360](https://github.com/amruthpillai/reactive-resume/issues/3360)) [14c7c0651](https://github.com/amruthpillai/reactive-resume/commit/14c7c0651) * Counted successful public PDF downloads in resume statistics. ([#3366](https://github.com/amruthpillai/reactive-resume/issues/3366)) [cddb01f03](https://github.com/amruthpillai/reactive-resume/commit/cddb01f03) * Added `ROOT_RESUME_ID` so self-hosters can publish one resume directly at the site root. [744eaa902](https://github.com/amruthpillai/reactive-resume/commit/744eaa902) * Replaced resume-specific social preview images with a neutral preview and hid the “build your own resume” signup link when registration is disabled. ([#3359](https://github.com/amruthpillai/reactive-resume/issues/3359), [#3401](https://github.com/amruthpillai/reactive-resume/issues/3401)) [0878b256a](https://github.com/amruthpillai/reactive-resume/commit/0878b256a), [18b5aa474](https://github.com/amruthpillai/reactive-resume/commit/18b5aa474) * Added password confirmation, labels, and immediate validation to resume sharing, including the documented minimum length. ([#3370](https://github.com/amruthpillai/reactive-resume/issues/3370)) [321f2fb43](https://github.com/amruthpillai/reactive-resume/commit/321f2fb43) * Fixed label targeting for Slug, Tags, Sidebar Width, and related form controls. Thanks to [@santhiprakash](https://github.com/santhiprakash). ([#3369](https://github.com/amruthpillai/reactive-resume/issues/3369)) [ea3980cba](https://github.com/amruthpillai/reactive-resume/commit/ea3980cba) * Added accessible labels to remaining website and picture inputs and restored hover feedback on primary buttons. ([#3251](https://github.com/amruthpillai/reactive-resume/issues/3251)) [5a6f5d4d6](https://github.com/amruthpillai/reactive-resume/commit/5a6f5d4d6), [ddbbbde80](https://github.com/amruthpillai/reactive-resume/commit/ddbbbde80) * Improved the builder's screen-reader outline with entry and nested-role headings, semantic rich text, safe links, stable section order, and correct handling of hidden content. This advances [#2844](https://github.com/amruthpillai/reactive-resume/issues/2844); public viewer and exported-document accessibility remain separate work. [9f0202eac](https://github.com/amruthpillai/reactive-resume/commit/9f0202eac), [acd2a9cfe](https://github.com/amruthpillai/reactive-resume/commit/acd2a9cfe) ## Self-Hosting & Integrations * Restored MCP OAuth dynamic client registration and resource-aware authorization. A new consent screen shows the signed-in account and requesting client, requires an explicit Allow or Deny decision, and preserves signed requests through login, registration, social authentication, passkeys, and two-factor authentication. Existing OAuth rows survive the upgrade, but previously registered clients must reconnect to establish resource grants. ([#3392](https://github.com/amruthpillai/reactive-resume/issues/3392)) [fe9b59e11](https://github.com/amruthpillai/reactive-resume/commit/fe9b59e11) * Added the OAuth provider tables required by Better Auth and aligned the account schema with Better Auth 1.7.3 while preserving existing issuer values. [fe9b59e11](https://github.com/amruthpillai/reactive-resume/commit/fe9b59e11), [cea27a97b](https://github.com/amruthpillai/reactive-resume/commit/cea27a97b) * Supported S3-compatible buckets that have object ACLs disabled. [35cecf9c9](https://github.com/amruthpillai/reactive-resume/commit/35cecf9c9) * Loaded local environment overrides correctly in Docker Compose. ([#3361](https://github.com/amruthpillai/reactive-resume/issues/3361)) [53288fcd3](https://github.com/amruthpillai/reactive-resume/commit/53288fcd3) * Exposed the running application version through the health endpoint. ([#3347](https://github.com/amruthpillai/reactive-resume/issues/3347)) [cd1c597ff](https://github.com/amruthpillai/reactive-resume/commit/cd1c597ff) * Invalidated cached build tasks when consumed workspace source changes, preventing stale application builds. [7390c81b7](https://github.com/amruthpillai/reactive-resume/commit/7390c81b7) * Added `AI_TEST_TIMEOUT_MS` for slower AI-provider health checks. Thanks to [@santhiprakash](https://github.com/santhiprakash). ([#3374](https://github.com/amruthpillai/reactive-resume/issues/3374)) [861ba8bf6](https://github.com/amruthpillai/reactive-resume/commit/861ba8bf6) * Rejected invalid resume writes instead of silently coercing values outside the published schema. ([#3368](https://github.com/amruthpillai/reactive-resume/issues/3368)) [779ea5cb4](https://github.com/amruthpillai/reactive-resume/commit/779ea5cb4) * Preserved optional Nodemailer settings in strict TypeScript configurations. [165841af4](https://github.com/amruthpillai/reactive-resume/commit/165841af4) * Refreshed interface and documentation copy, synchronized translation catalogs from Crowdin, and updated workspace dependencies. [f29b92e2f](https://github.com/amruthpillai/reactive-resume/commit/f29b92e2f), [d277518d2](https://github.com/amruthpillai/reactive-resume/commit/d277518d2), [7fef84078](https://github.com/amruthpillai/reactive-resume/commit/7fef84078), [e272037be](https://github.com/amruthpillai/reactive-resume/commit/e272037be) **Full Changelog**: [v5.2.9...v5.3.0](https://github.com/amruthpillai/reactive-resume/compare/v5.2.9...v5.3.0) ## Highlights * **A free ATS checker that never uploads your resume.** Drop a PDF on [rxresu.me/ats-checker](https://rxresu.me/ats-checker) and it opens the file the way a parser would, pulls the text out, and reports what survived: whether the file carries real text or a picture of one, whether a multi-column layout scrambles the reading order, and whether your name, email, phone, links and dates come through intact. Everything runs in your browser — the file is never uploaded, nothing is stored, and no account is needed. Paste a job description and it will also tell you which of the posting's terms already appear in your resume. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * **A score you can actually audit.** The report gives one number from 0 to 100 across readability, layout, sections, contact details and dates — and shows its working. Every finding cites the text that triggered it and the page it sits on, and the report states how many checks ran and how many were honestly skipped rather than quietly counting them as passes. Employment gaps, writing style and length are reported as unscored tips; they never move the score. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * **Resume analysis has been replaced by the ATS check.** The old AI-scored analysis is gone, along with its stored results, its `get_resume_analysis` MCP tool, and the `POST /ai/analyze-resume` endpoint. What replaces it is deterministic and evidence-backed, with an optional AI second opinion on your writing that deliberately returns no score of its own. Self-hosters: read the upgrade note below. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * **Bold text finally looks bold.** Most resumes pair Regular with SemiBold, which rendered `` almost indistinguishably from body text. Bold now resolves to the font family's true Bold face, so emphasis reads as emphasis — existing resumes will export with visibly stronger bold text. Thanks to [@santhiprakash](https://github.com/santhiprakash). [e065a1082](https://github.com/amruthpillai/reactive-resume/commit/e065a1082) ## Resume Builder * The right sidebar's **ATS Check** section now runs live checks against your resume as you type — missing dates, malformed links, prose stranded in a narrow sidebar — before you export anything. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * **Run deep check** renders your current resume to a PDF in your browser and runs the full file check against those exact bytes, which is the same file a recruiter receives. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * Once a report exists, you can ask your own AI provider to review the writing — weak phrasing, bullets that describe duties rather than outcomes, and where a rewrite would land better. It sends only the extracted text, never the PDF. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * Section detection understands more of the headings people actually use, so conventional sections are recognized across a wider range of resumes. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * Toasts no longer slide underneath dialogs and sheets. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) ## AI Agent * Picking a provider when starting a thread now uses the same provider picker as the rest of the app, showing the label, provider and model consistently instead of one long concatenated line. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) ## PDF Export & Fonts * Bold text now uses the font family's true Bold face. Most resumes store their typography as Regular plus SemiBold, which rendered `` almost indistinguishably from body text on faces like Open Sans; bold now resolves to the family's 700 weight where it has one, and to its heaviest bold-class face where it does not. Existing resumes will export with visibly stronger bold text. Thanks to [@santhiprakash](https://github.com/santhiprakash). [e065a1082](https://github.com/amruthpillai/reactive-resume/commit/e065a1082) * Long bullet-list lines no longer spill past the page margin. Thanks to [@santhiprakash](https://github.com/santhiprakash). [a416d0111](https://github.com/amruthpillai/reactive-resume/commit/a416d0111) * Emoji render instead of dropping out as blank boxes. They are drawn as monochrome outlines, because the color emoji format cannot be embedded in a PDF, and the fallback font is only loaded when your resume actually contains emoji. Thanks to [@santhiprakash](https://github.com/santhiprakash). [b47f80532](https://github.com/amruthpillai/reactive-resume/commit/b47f80532) * Vazirmatn is available in the font catalog again, so Persian and Arabic resumes that ask for it no longer fall back to a Latin serif and lose their glyphs on export. Thanks to [@santhiprakash](https://github.com/santhiprakash). [2761bd671](https://github.com/amruthpillai/reactive-resume/commit/2761bd671) ## Self-Hosting & Maintenance * **A migration drops the `resume_analysis` table.** Any saved analyses are deleted when you upgrade; they have no equivalent in the new report, which is computed on demand rather than stored. No action is needed beyond the usual upgrade. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * **Two API surfaces were removed.** MCP clients calling `get_resume_analysis` and API clients calling `POST /ai/analyze-resume` will start failing; the replacement is `POST /ai/ats-review`, which reviews extracted resume text and returns qualitative feedback without a score. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * `/ats-checker` is listed in the sitemap and carries its own preview card, so the page is indexable and shares cleanly. [#3382](https://github.com/amruthpillai/reactive-resume/pull/3382) * Routine dependency updates across the workspace, including the AI SDK providers, Better Auth, TipTap, TanStack Query, Hono and the build toolchain. All patch and minor releases; no breaking upgrades. * Translations synced from Crowdin, with the new ATS checker strings covered across every supported language. [7fac6f29c](https://github.com/amruthpillai/reactive-resume/commit/7fac6f29c) **Full Changelog**: [v5.2.8...v5.2.9](https://github.com/amruthpillai/reactive-resume/compare/v5.2.8...v5.2.9) ## Highlights * **The AI agent now asks before it edits your resume.** Changes arrive as a proposal you approve or reject, so you see what the assistant wants to touch before anything is written. Once you trust a conversation, you can turn the review step off for that thread alone. The agent also survives a server restart mid-reply instead of leaving the thread stuck, and long conversations are trimmed as they grow so they keep working past the point they used to stall. [c8081ac2f](https://github.com/amruthpillai/reactive-resume/commit/c8081ac2f) * **Custom Styles can finally reach every item header.** `item-header` used to match only some sections, and on stacked headers only the first row — certifications, awards, projects, publications and references quietly ignored it. It now covers the full header row of every section on every template, and a new `item-header-row` part lets you stop a long title from pushing its trailing date onto a line of its own. [4d53a6d1d](https://github.com/amruthpillai/reactive-resume/commit/4d53a6d1d), [00be67f70](https://github.com/amruthpillai/reactive-resume/commit/00be67f70) * **Self-hosters using a custom OAuth provider must update one URL.** The callback path changed from `/api/auth/oauth2/callback/custom` to `/api/auth/callback/custom`. Update the redirect URI registered with your identity provider before upgrading, or custom sign-in will fail. Installs that use `OAUTH_DISCOVERY_URL` need one additional SQL statement — both steps are written up in the [SSO documentation](https://docs.rxresu.me/self-hosting/sso). [bdac806c7](https://github.com/amruthpillai/reactive-resume/commit/bdac806c7) ## AI Agent * Resume edits are gated behind an approval step, with a per-conversation setting to skip it once you are comfortable. Tool activity, token usage, and each step the assistant takes are now visible in the thread. [c8081ac2f](https://github.com/amruthpillai/reactive-resume/commit/c8081ac2f) * Copying a conversation as JSON no longer embeds full resume documents, so the file stays small and your resume content does not travel with a transcript you might paste elsewhere. [8ce899a04](https://github.com/amruthpillai/reactive-resume/commit/8ce899a04) * Resume analysis is told today's date, so it no longer misjudges how recent your most recent role is. Thanks to [@emanuelet](https://github.com/emanuelet). [#3353](https://github.com/amruthpillai/reactive-resume/pull/3353) * Agent edits to a newly created resume no longer fail permanently with a version conflict. [39f36b4ac](https://github.com/amruthpillai/reactive-resume/commit/39f36b4ac) ## Custom Styles * `item-header` now applies to the whole header row of every section on every template, instead of being silently dropped on sections whose header did not start with the one element it looked for. Rendered output is unchanged apart from the rows that should have been styled all along. [4d53a6d1d](https://github.com/amruthpillai/reactive-resume/commit/4d53a6d1d) * Added `template-part[name="item-header-row"]`, the split row holding a title and its trailing date. Set `flex-wrap: nowrap` on it to keep the date pinned right down a long list of certifications. [00be67f70](https://github.com/amruthpillai/reactive-resume/commit/00be67f70) * Under `nowrap`, long item titles no longer overlap the date beside them. [ebcaa4729](https://github.com/amruthpillai/reactive-resume/commit/ebcaa4729) ## Accounts & Sign-in * Disconnecting a linked provider works again. Sessions last a week, but the unlink endpoint rejected any session older than a day, so the button failed for nearly everyone. [39590eaff](https://github.com/amruthpillai/reactive-resume/commit/39590eaff) * Sign-in and account errors now show the actual reason instead of collapsing to a generic message. [39590eaff](https://github.com/amruthpillai/reactive-resume/commit/39590eaff) * Sign-in failures that happen before your provider can redirect you now land on a proper page explaining what went wrong, translated into every supported language, rather than a wall of JSON. [bdac806c7](https://github.com/amruthpillai/reactive-resume/commit/bdac806c7), [b960e3273](https://github.com/amruthpillai/reactive-resume/commit/b960e3273) ## Self-Hosting & Maintenance * Upgraded to Better Auth 1.7. Beyond the callback URL change above, accounts are now identified by the issuer your provider advertises; the startup migration backfills existing accounts and refuses to proceed if the backfill would merge two accounts together. [bdac806c7](https://github.com/amruthpillai/reactive-resume/commit/bdac806c7) * The DeepSeek Harness plugin now lives in this repository and is published from it. It reads MCP tool names directly from the server, so a renamed tool breaks its prompt guide in the same pull request rather than days later through a scheduled job. [65618a82a](https://github.com/amruthpillai/reactive-resume/commit/65618a82a) * Routine dependency updates across the workspace, including the AI SDK providers, the PDF renderer, and the build toolchain. [8ffe50a58](https://github.com/amruthpillai/reactive-resume/commit/8ffe50a58) **Full Changelog**: [v5.2.7...v5.2.8](https://github.com/amruthpillai/reactive-resume/compare/v5.2.7...v5.2.8) ## Highlights * **Custom Styles now compile in your browser.** Semantic CSS is compiled and resolved locally for the editor, preview, public resumes, and exports, so diagnostics appear as you type instead of after a save and a server round-trip. Self-hosted servers no longer run a stylesheet preflight worker on every edit, and server-side PDF generation stays available as a fallback when a browser cannot render locally. [9509b5bc2](https://github.com/amruthpillai/reactive-resume/commit/9509b5bc2) * **Shared resume links now unfurl with a preview card.** Posting a public resume link to X, LinkedIn, Slack, or any chat app shows the name, headline, and template preview instead of a bare URL. The homepage's own card and structured data reach crawlers again — the static file handler had been answering the root request before the code that injects them could run. [9d0dc3670](https://github.com/amruthpillai/reactive-resume/commit/9d0dc3670), [36c35c9bd](https://github.com/amruthpillai/reactive-resume/commit/36c35c9bd) * **The AI agent asks instead of guessing.** When a request is ambiguous, the assistant now offers a short set of choices inline in the chat rather than picking an interpretation and running with it. [eedf2faf0](https://github.com/amruthpillai/reactive-resume/commit/eedf2faf0) ## Sharing & Search * Twitter card tags are declared with the attribute X actually reads, so the title, description, and banner image appear in link previews again. [1e23a453a](https://github.com/amruthpillai/reactive-resume/commit/1e23a453a) * Resume preview cards are built only for resumes that are public and not password-protected, and generating one no longer counts as a visit in your statistics. [9d0dc3670](https://github.com/amruthpillai/reactive-resume/commit/9d0dc3670) * Shortened the site description so it is no longer cut off in mobile search results. [d0fa9ae8d](https://github.com/amruthpillai/reactive-resume/commit/d0fa9ae8d) ## AI Agent * Added inline questions with selectable answers, along with a clearer empty state when a thread has no messages yet. [eedf2faf0](https://github.com/amruthpillai/reactive-resume/commit/eedf2faf0) * The message box keeps focus after you send, so you can keep typing while a reply streams in instead of clicking back into it. [7c7dbaf21](https://github.com/amruthpillai/reactive-resume/commit/7c7dbaf21) * Fixed a rendering bug that could duplicate or drop parts of a long, multi-step reply as it streamed. [762b999d1](https://github.com/amruthpillai/reactive-resume/commit/762b999d1) ## Job Applications * Application auto-fill now works from a pasted job posting instead of a URL. Fetching arbitrary URLs from the server meant owning redirect, size, and private-address defences plus per-site scraping quirks, so the URL field has been removed — paste the posting text and the fields below it are filled in as before. Auto-fill is offered only when an AI provider is configured and tested, and only for a paste long enough to be a real posting. [da2f1f824](https://github.com/amruthpillai/reactive-resume/commit/da2f1f824) ## Settings & Interface * **Danger Zone** is now **Account**, at `/dashboard/settings/account`, since the page covers account-level actions rather than only destructive ones. [7a14b0dfb](https://github.com/amruthpillai/reactive-resume/commit/7a14b0dfb) * API keys created without an expiry date are listed again instead of disappearing from the key list. [8affc567e](https://github.com/amruthpillai/reactive-resume/commit/8affc567e) * Testing an AI provider is now time-bounded and reports why it failed, so a rejected key, a wrong model name, and an unreachable host are no longer indistinguishable from a connection that appears stuck. Thanks to [@MrTig-afk](https://github.com/MrTig-afk). [#3319](https://github.com/amruthpillai/reactive-resume/pull/3319) * Rebuilt the notification toasts on the same component library as the rest of the interface, for consistent styling, stacking, and screen-reader behaviour. [170550ed5](https://github.com/amruthpillai/reactive-resume/commit/170550ed5), [23ceee214](https://github.com/amruthpillai/reactive-resume/commit/23ceee214), [e2554c9be](https://github.com/amruthpillai/reactive-resume/commit/e2554c9be) ## Reliability, Self-Hosting & Maintenance * The server no longer carries the stylesheet control plane — apply state, preflight, revisions, render-data versions, and mismatch negotiation are gone, along with the unused resume columns that backed them. Expect lower memory and CPU use on instances where Custom Styles are in active use. [9509b5bc2](https://github.com/amruthpillai/reactive-resume/commit/9509b5bc2) * The conflict-marker pre-commit check now runs correctly on Windows. Thanks to [@MrTig-afk](https://github.com/MrTig-afk). [#3320](https://github.com/amruthpillai/reactive-resume/pull/3320) * Test suites are isolated from one another and the OpenAPI specification is built once per suite, removing a class of order-dependent failures and timeouts that made local runs unreliable. [e8508e6d0](https://github.com/amruthpillai/reactive-resume/commit/e8508e6d0), [60d044076](https://github.com/amruthpillai/reactive-resume/commit/60d044076), [bfdd29f94](https://github.com/amruthpillai/reactive-resume/commit/bfdd29f94), [ac062bbcb](https://github.com/amruthpillai/reactive-resume/commit/ac062bbcb) * Organized GitHub issue triage. [#3325](https://github.com/amruthpillai/reactive-resume/pull/3325) * Synced the latest Crowdin translation catalogs. [#3327](https://github.com/amruthpillai/reactive-resume/pull/3327), [#3328](https://github.com/amruthpillai/reactive-resume/pull/3328), [#3330](https://github.com/amruthpillai/reactive-resume/pull/3330) * Refreshed workspace dependencies and development tooling. [9dc2aade4](https://github.com/amruthpillai/reactive-resume/commit/9dc2aade4) **Full Changelog**: [v5.2.6...v5.2.7](https://github.com/amruthpillai/reactive-resume/compare/v5.2.6...v5.2.7) ## Highlights * **Check your resume's ATS parseability as you edit.** The builder now runs a deterministic, private check in your browser for contact details, dates, section structure, reading order, font size, line height, and margins. Findings explain what to change and can jump directly to the affected field. Thanks to [@Syed-Ali-Abbas-Zaidi](https://github.com/Syed-Ali-Abbas-Zaidi). [#3314](https://github.com/amruthpillai/reactive-resume/pull/3314) * **Download cover letters through MCP.** AI clients can now request a short-lived PDF download URL for either a resume or its visible cover letter. The selected document is cryptographically bound to the URL, so it cannot be switched after signing. Thanks to [@ignaciocarre](https://github.com/ignaciocarre). [#3304](https://github.com/amruthpillai/reactive-resume/pull/3304) * **Clearer JSON imports.** Reactive Resume, Reactive Resume v4, and JSON Resume files are detected and routed to the correct parser, while malformed files now produce concise, readable validation messages instead of raw error dumps. Thanks to [@MrTig-afk](https://github.com/MrTig-afk). [#3296](https://github.com/amruthpillai/reactive-resume/pull/3296) * **Semantic CSS is now the standard Custom Styles experience.** New resumes use it by default, the legacy feature flag and banner have been removed, and explicit activation no longer fails on an obsolete legacy-renderer parity check. [3589b534f](https://github.com/amruthpillai/reactive-resume/commit/3589b534f), [#3316](https://github.com/amruthpillai/reactive-resume/pull/3316) ## Resume Builder & PDF Exports * Fixed missing spaces around bold rich text in PDF exports without changing quoted HTML attributes. Thanks to [@shehraan](https://github.com/shehraan). [#3273](https://github.com/amruthpillai/reactive-resume/pull/3273) * Added Noto punctuation fallbacks so bullets and other punctuation render correctly when the selected Latin font does not contain those glyphs. Thanks to [@santhiprakash](https://github.com/santhiprakash). [#3294](https://github.com/amruthpillai/reactive-resume/pull/3294) * Stopped empty or whitespace-only skill proficiency values from producing phantom PDF text nodes in the Gengar template. Thanks to [@santhiprakash](https://github.com/santhiprakash). [#3289](https://github.com/amruthpillai/reactive-resume/pull/3289) * The icon picker once again lets you choose the empty option to remove an icon. Thanks to [@garudaccs](https://github.com/garudaccs). [#3298](https://github.com/amruthpillai/reactive-resume/pull/3298) * Panning the builder canvas now releases focus from the active field, preventing accidental edits while navigating the preview. Thanks to [@Syed-Ali-Abbas-Zaidi](https://github.com/Syed-Ali-Abbas-Zaidi). [#3303](https://github.com/amruthpillai/reactive-resume/pull/3303) * The template gallery now uses fast, stable preview images instead of rendering every template live. [#3302](https://github.com/amruthpillai/reactive-resume/pull/3302) * Moving from the import dialog to AI provider settings now asks for confirmation before discarding the current import. Thanks to [@Syed-Ali-Abbas-Zaidi](https://github.com/Syed-Ali-Abbas-Zaidi). [#3308](https://github.com/amruthpillai/reactive-resume/pull/3308) ## AI, Authentication & Integrations * Stopping or archiving an AI agent run now cancels it cleanly instead of surfacing an unhandled stream error that could terminate the server. [04100aa9e](https://github.com/amruthpillai/reactive-resume/commit/04100aa9e) * Social sign-in can create an account directly when registration is enabled, removing the need to visit the registration screen first. [2d6ea9ce8](https://github.com/amruthpillai/reactive-resume/commit/2d6ea9ce8) * MCP OAuth JWT verification now uses the server's loopback JWKS endpoint, fixing verification on deployments whose public URL cannot be reached from inside the container. Thanks to [@santhiprakash](https://github.com/santhiprakash). [#3297](https://github.com/amruthpillai/reactive-resume/pull/3297) ## Reliability, Accessibility & Self-Hosting * Semantic CSS PDF preflight now warms and reuses one worker instead of cold-starting a renderer for every edit, making style activation reliable on slower or CPU-constrained servers. [e6a31aab9](https://github.com/amruthpillai/reactive-resume/commit/e6a31aab9) * Unhandled promise rejections are logged without taking down the entire Node.js process; uncaught exceptions continue to use Node's fail-fast behavior. [efd950bd9](https://github.com/amruthpillai/reactive-resume/commit/efd950bd9) * Restored consistent PDF line metrics after the React PDF dependency update, preserving the established browser-to-PDF layout. [b4f245a38](https://github.com/amruthpillai/reactive-resume/commit/b4f245a38) * Added an accessible label to the two-factor secret copy button, restored visible keyboard focus in the template gallery, and prevented duplicate API keys from double submission. [ba1f46995](https://github.com/amruthpillai/reactive-resume/commit/ba1f46995) * Production and development containers now use the official pnpm image, and the contributor guide documents the matching Docker and `dotenvx` workflows. [28d698635](https://github.com/amruthpillai/reactive-resume/commit/28d698635) ## Documentation & Localization * Corrected the development guide's environment, migration, and app-name instructions. Thanks to [@santhiprakash](https://github.com/santhiprakash). [#3286](https://github.com/amruthpillai/reactive-resume/pull/3286), [#3287](https://github.com/amruthpillai/reactive-resume/pull/3287) * Clarified the Redis URLs and Compose startup order used by repository automation and development agents. Thanks to [@santhiprakash](https://github.com/santhiprakash). [#3288](https://github.com/amruthpillai/reactive-resume/pull/3288) * Synced the latest Crowdin translation catalogs. [#3280](https://github.com/amruthpillai/reactive-resume/pull/3280), [#3281](https://github.com/amruthpillai/reactive-resume/pull/3281), [#3315](https://github.com/amruthpillai/reactive-resume/pull/3315) * Refreshed workspace dependencies and development tooling. **Full Changelog**: [v5.2.5...v5.2.6](https://github.com/amruthpillai/reactive-resume/compare/v5.2.5...v5.2.6) ## Highlights * **Custom Styles are now Semantic CSS.** Custom Styles use a new CSS-like language built for resume PDFs. Selectors describe resume content — `section[type="experience"]`, `region[placement="sidebar"]`, `field[name="position"]`, `list-marker` — instead of a template's internal markup, so a stylesheet keeps working across templates and can be copied between resumes. Builder settings are exposed as read-only `--resume-*` variables, and the editor keeps your draft, status, undo history, and last valid stylesheet separate so a broken rule never replaces a working PDF. [d2ffbf961](https://github.com/amruthpillai/reactive-resume/commit/d2ffbf961) * **Editable application timeline.** Application history is now a real timeline you can curate: add a note with its own date, edit or delete an entry, and see which stage each entry belongs to, alongside a stage-entered date. Available in the app and through MCP. [18d0c14aa](https://github.com/amruthpillai/reactive-resume/commit/18d0c14aa) * **LinkedIn job posting auto-fill.** Pasting a LinkedIn job URL into an application now fills in the title, company, location, and description directly from the posting. [47349e7ab](https://github.com/amruthpillai/reactive-resume/commit/47349e7ab) * **A faster homepage.** Homepage SEO metadata is rendered by the server on the first response, and the hero video no longer sits on the largest-contentful-paint path. [418c7887e](https://github.com/amruthpillai/reactive-resume/commit/418c7887e), [1e665fbe7](https://github.com/amruthpillai/reactive-resume/commit/1e665fbe7) ## Custom Styles (Semantic CSS) * Added the Semantic CSS editor under **Design → Custom Styles**, with live status, error line and column numbers, "selector matches nothing" warnings, stylesheet undo and redo, **Reset to applied stylesheet**, **Copy stylesheet**, and a focus mode that opens full-width on mobile. [d2ffbf961](https://github.com/amruthpillai/reactive-resume/commit/d2ffbf961) * Resumes still using the previous Custom Styles form get a converted stylesheet draft to review; the original legacy rules stay active until you select **Activate Semantic CSS**, and remain available for rollback. [d2ffbf961](https://github.com/amruthpillai/reactive-resume/commit/d2ffbf961) * Added semantic selectors, attributes, and template-specific parts for all 15 templates, plus pagination and page-size controls (`break-inside`, `orphans`, `widows`, `-resume-min-presence-ahead`, `size`) and PDF-dimension media queries. [d2ffbf961](https://github.com/amruthpillai/reactive-resume/commit/d2ffbf961) * New resumes start in Semantic CSS mode automatically, while existing legacy styles remain active until their converted draft is explicitly activated. * Invalid style intents are now filtered out instead of discarding the whole rule set, so one bad entry no longer drops your valid custom styles. [689e7e24d](https://github.com/amruthpillai/reactive-resume/commit/689e7e24d) * Custom style numeric inputs are clamped to their supported ranges. [2a0782517](https://github.com/amruthpillai/reactive-resume/commit/2a0782517) * Award titles can now be un-bolded through custom styles. [08d859010](https://github.com/amruthpillai/reactive-resume/commit/08d859010) ## Application Tracker * Added timeline entry creation with a custom date, plus update and delete for individual entries, across the API, the detail sheet, and MCP tools. [18d0c14aa](https://github.com/amruthpillai/reactive-resume/commit/18d0c14aa) * Job posting fetches now work with HTTPS postings that previously failed to load. [d4cf260ae](https://github.com/amruthpillai/reactive-resume/commit/d4cf260ae) ## AI & Integrations * The model for a saved AI provider can now be edited inline from settings, instead of deleting and re-adding the provider. [47349e7ab](https://github.com/amruthpillai/reactive-resume/commit/47349e7ab) * Fixed the OAuth protected-resource metadata so MCP clients receive the correct authorization server list. [1124d3dfd](https://github.com/amruthpillai/reactive-resume/commit/1124d3dfd) ## Resume Builder & PDF Exports * Fixed rich-text editing in the builder, where `Enter` and list editing had stopped working. [b303b8975](https://github.com/amruthpillai/reactive-resume/commit/b303b8975) * Page margin values are clamped to 0–100, so pasting an out-of-range value no longer crashes the builder. [4ac19f81b](https://github.com/amruthpillai/reactive-resume/commit/4ac19f81b) * The profile picture delete icon now clears the image correctly. [0eb9ce012](https://github.com/amruthpillai/reactive-resume/commit/0eb9ce012) * Fixed list markers and bullet indentation when a list splits across a page break in the exported PDF. [ed5d10c49](https://github.com/amruthpillai/reactive-resume/commit/ed5d10c49), [d536b1921](https://github.com/amruthpillai/reactive-resume/commit/d536b1921) * Fixed skill name sizing so long skill names lay out correctly in PDF exports. [e34e7be6e](https://github.com/amruthpillai/reactive-resume/commit/e34e7be6e) ## Performance & SEO * The homepage now ships SEO metadata in the initial server response, resolved against the instance's public URL. [418c7887e](https://github.com/amruthpillai/reactive-resume/commit/418c7887e), [50f50b267](https://github.com/amruthpillai/reactive-resume/commit/50f50b267) * The homepage hero now loads a poster image first and takes the video off the LCP path. [1e665fbe7](https://github.com/amruthpillai/reactive-resume/commit/1e665fbe7) * The PDF renderer is loaded lazily on the server, cutting cold-start time for instances that are not exporting a PDF yet. [bb1fb3a7d](https://github.com/amruthpillai/reactive-resume/commit/bb1fb3a7d) ## Reliability & Self-Hosting * Fixed OAuth sign-in mapping the session to the account id instead of the user id. [34c03b1f7](https://github.com/amruthpillai/reactive-resume/commit/34c03b1f7) * Limited immutable cache headers to hashed media assets so mutable uploads are no longer cached indefinitely. [dd0531091](https://github.com/amruthpillai/reactive-resume/commit/dd0531091) * Preserved the Cloudflare Rocket Loader exclusion and the bootstrap script attribute order through the production build. [93c06934b](https://github.com/amruthpillai/reactive-resume/commit/93c06934b), [048eab3b4](https://github.com/amruthpillai/reactive-resume/commit/048eab3b4) * Simplified URL security checks, shared template styles, and test fixtures, removing roughly 1,000 lines of redundant code. [9110e8699](https://github.com/amruthpillai/reactive-resume/commit/9110e8699) * Refreshed workspace dependencies. [326606682](https://github.com/amruthpillai/reactive-resume/commit/326606682), [164a27930](https://github.com/amruthpillai/reactive-resume/commit/164a27930) ## Documentation & Localization * Rewrote the Custom Styles guide as **Applying Custom Styles**, covering conversion, selectors, builder variables, pagination, diagnosis, and portability. The JSON Resume schema guide and the resume-builder skill schema reference are now generated from the schema so they stay in sync. [d2ffbf961](https://github.com/amruthpillai/reactive-resume/commit/d2ffbf961) * Added 17 comparison pages covering Reactive Resume against mainstream resume builders, AI and ATS tools, design editors, and career and template services. [9d6426b2e](https://github.com/amruthpillai/reactive-resume/commit/9d6426b2e) * Canonicalized the getting started routes and fixed the contributing guide's troubleshooting code blocks. [a4897c20d](https://github.com/amruthpillai/reactive-resume/commit/a4897c20d), [e6b4733c5](https://github.com/amruthpillai/reactive-resume/commit/e6b4733c5) * Pinned the v4 migration script checkout in the self-hosting migration guide, and aligned the documented pnpm version with the `packageManager` field. [ac9813909](https://github.com/amruthpillai/reactive-resume/commit/ac9813909), [15f8bce98](https://github.com/amruthpillai/reactive-resume/commit/15f8bce98) * Synced Crowdin translation catalogs, including strings for the application timeline. [9085a199c](https://github.com/amruthpillai/reactive-resume/commit/9085a199c), [79e4a3ddc](https://github.com/amruthpillai/reactive-resume/commit/79e4a3ddc), [d50948dde](https://github.com/amruthpillai/reactive-resume/commit/d50948dde) **Full Changelog**: [v5.2.3...v5.2.5](https://github.com/amruthpillai/reactive-resume/compare/v5.2.3...v5.2.5) ## Highlights * **More AI provider choices.** The AI settings page now supports Mistral AI, Cohere, xAI Grok, Groq, DeepSeek, Together.ai, Fireworks, Cerebras, and Perplexity, with provider defaults filled in for each. Ollama is now labeled as Ollama Cloud to make the hosted integration clearer. * **Cleaner cover-letter exports.** Cover-letter PDF, DOCX, and Markdown downloads now export the letter without resume header chrome by default, and PDF downloads include a new toggle for adding the resume header back when needed. [8570c1c70](https://github.com/amruthpillai/reactive-resume/commit/8570c1c70) * **More accurate public resume statistics.** Rapid repeat views from the same client are now de-duplicated before incrementing public resume view counts. [97ab3c973](https://github.com/amruthpillai/reactive-resume/commit/97ab3c973) ## AI & Integrations * Added first-class AI SDK support for Mistral AI, Cohere, xAI, Groq, DeepSeek, Together.ai, Fireworks, Cerebras, and Perplexity across saved provider settings and AI service calls. * Made AI provider connection tests work with OpenAI-compatible models that do not support structured output, with a clearer error when a model returns too much text during the test. * Published Reactive Resume MCP registry metadata so MCP clients and directories can discover the hosted remote server. [73daf22b2](https://github.com/amruthpillai/reactive-resume/commit/73daf22b2) ## Resume Builder & Exports * Fixed cover-letter-only exports across PDF, DOCX, and Markdown so they no longer include resume contact details or a redundant cover-letter heading. [8570c1c70](https://github.com/amruthpillai/reactive-resume/commit/8570c1c70) * Added an **Include resume header** option for cover-letter PDF downloads. * Improved the layout page header so the **Full Width** and **Delete Page** controls fit better in narrow builder sidebars. * Simplified the current-template card by removing its hover live preview; template switching still opens the full template gallery. ## Reliability & Self-Hosting * Added report-only CSP, frame blocking, `nosniff`, and stricter referrer headers to web app shell responses, and tightened public upload headers to rely on same-site resource policy instead of an unconditional CORS header. [9bde7d544](https://github.com/amruthpillai/reactive-resume/commit/9bde7d544) * Limited application bulk update and delete requests to 200 selected items per operation to avoid oversized bulk actions. [c9b3fa5c1](https://github.com/amruthpillai/reactive-resume/commit/c9b3fa5c1) * Resume lock and password mutations now return `NOT_FOUND` when the resume is missing instead of silently succeeding. [e47cf6e77](https://github.com/amruthpillai/reactive-resume/commit/e47cf6e77) * Reduced repeated work in the font picker by computing the font family options once per app process. [7e0657946](https://github.com/amruthpillai/reactive-resume/commit/7e0657946) * Refreshed workspace dependencies, including AI SDK provider packages, Lingui, oRPC, Hono, Tiptap, and test tooling. ## Documentation & Localization * Tightened SEO titles and descriptions across the documentation site. [5270a2a9a](https://github.com/amruthpillai/reactive-resume/commit/5270a2a9a) * Corrected the README feature list to describe structured Style Rules instead of custom CSS. [66078609a](https://github.com/amruthpillai/reactive-resume/commit/66078609a) * Synced Crowdin translation catalogs and added locale strings for the new AI providers and cover-letter export option. [b87a9d828](https://github.com/amruthpillai/reactive-resume/commit/b87a9d828), [25021507a](https://github.com/amruthpillai/reactive-resume/commit/25021507a) **Full Changelog**: [v5.2.2...v5.2.3](https://github.com/amruthpillai/reactive-resume/compare/v5.2.2...v5.2.3) ## Highlights * **Application Tracker REST and MCP parity.** The job application pipeline is now available outside the web app through authenticated REST endpoints and MCP tools, so agents can create records, import rows, move stages, add notes, manage follow-ups, attach sent PDFs, and inspect pipeline health. [2dad27da5](https://github.com/amruthpillai/reactive-resume/commit/2dad27da5), [bf2dc5bbd](https://github.com/amruthpillai/reactive-resume/commit/bf2dc5bbd) * **Agent-only application tracking.** MCP clients can now operate the Application Tracker end to end, including Application Copilot actions for job auto-fill, match scoring, tailored resume copies, cover letters, and recruiter follow-ups. [bf2dc5bbd](https://github.com/amruthpillai/reactive-resume/commit/bf2dc5bbd), [93abb1102](https://github.com/amruthpillai/reactive-resume/commit/93abb1102) * **New application MCP guide.** The docs now include a dedicated guide with practical prompts for using Reactive Resume MCP to manage applications from an AI client. ## Application Tracker API * Added public REST coverage for listing, reading, creating, updating, importing, bulk-updating, bulk-deleting, tagging, and summarizing job applications. [2dad27da5](https://github.com/amruthpillai/reactive-resume/commit/2dad27da5) * Added authenticated document endpoints for attaching and removing the resume or cover-letter PDF sent with an application. [2dad27da5](https://github.com/amruthpillai/reactive-resume/commit/2dad27da5), [fb3f40244](https://github.com/amruthpillai/reactive-resume/commit/fb3f40244) * Added REST endpoints for Application Copilot actions: job posting auto-fill, resume match scoring, tailored resume creation, and message drafting. [2dad27da5](https://github.com/amruthpillai/reactive-resume/commit/2dad27da5) * Updated the OpenAPI reference so application endpoints, multipart document uploads, statistics, and tags are visible in the docs. [fb3f40244](https://github.com/amruthpillai/reactive-resume/commit/fb3f40244) ## MCP & Agent Workflows * Added MCP tools for every Application Tracker workflow available in the app, including create, update, note, import, bulk action, archive, delete, document attachment, document removal, tag, statistics, and Application Copilot tools. [bf2dc5bbd](https://github.com/amruthpillai/reactive-resume/commit/bf2dc5bbd) * Improved MCP tool metadata so clients can distinguish safe reads, mutating actions, destructive actions, and AI-powered workflows more reliably. [93abb1102](https://github.com/amruthpillai/reactive-resume/commit/93abb1102) * Updated the resume-builder skill instructions so agents are told that Reactive Resume MCP can also manage job applications, not only resumes. [ac8734be3](https://github.com/amruthpillai/reactive-resume/commit/ac8734be3) ## Documentation & Reliability * Added a parity design note for the Application Tracker REST and MCP surfaces. [3868429ce](https://github.com/amruthpillai/reactive-resume/commit/3868429ce) * Documented application MCP automation in the MCP guide, including available tools, prompt examples, and troubleshooting for PDF attachments. [ed83a3f5e](https://github.com/amruthpillai/reactive-resume/commit/ed83a3f5e) * Preserved shared application documents when one application removes or replaces a file also referenced by another application. [3c9c5c8c2](https://github.com/amruthpillai/reactive-resume/commit/3c9c5c8c2) **Full Changelog**: [v5.2.1...v5.2.2](https://github.com/amruthpillai/reactive-resume/compare/v5.2.1...v5.2.2) ## Highlights * **Application Tracking is here.** Track every opportunity from saved role to offer with board, table, and insights views; search, filter, sort, tag, archive, and bulk-update applications without keeping a separate spreadsheet. [893df25af](https://github.com/amruthpillai/reactive-resume/commit/893df25af), [e99c1665d](https://github.com/amruthpillai/reactive-resume/commit/e99c1665d), [00a972155](https://github.com/amruthpillai/reactive-resume/commit/00a972155) * **Application Copilot.** Link a resume and job description to score your fit, create a tailored resume copy, draft a cover letter, or draft a recruiter follow-up from the application detail panel. [893df25af](https://github.com/amruthpillai/reactive-resume/commit/893df25af) * **Markdown export for resumes.** Export a resume as clean Markdown for docs, websites, AI workflows, or any place where plain text is easier to reuse than a PDF. [20c803e93](https://github.com/amruthpillai/reactive-resume/commit/20c803e93) * **A cleaner export flow.** Resume and cover-letter downloads now live in a dedicated dialog, with separate PDF, DOCX, JSON, and print actions. [20c803e93](https://github.com/amruthpillai/reactive-resume/commit/20c803e93) ## Application Tracking * Added the application data model, API routes, database schema, migrations, and service tests for storing applications, contacts, documents, follow-ups, timeline activity, tags, sources, salaries, and stages. [893df25af](https://github.com/amruthpillai/reactive-resume/commit/893df25af), [4ae6d8476](https://github.com/amruthpillai/reactive-resume/commit/4ae6d8476) * Added the dashboard Applications page with kanban board, table, insights dashboard, detail sheet, create/edit sheet, actions menu, file attachments, CSV import, and archived view. [893df25af](https://github.com/amruthpillai/reactive-resume/commit/893df25af), [00a972155](https://github.com/amruthpillai/reactive-resume/commit/00a972155) * Added CSV import from uploads or pasted rows, with header recognition, row validation, stage parsing, tag splitting, and importer tests. [893df25af](https://github.com/amruthpillai/reactive-resume/commit/893df25af) * Added application insights for pipeline counts, response rate, interviews, offers, funnel drop-off, weekly application volume, and source breakdowns. [893df25af](https://github.com/amruthpillai/reactive-resume/commit/893df25af), [00a972155](https://github.com/amruthpillai/reactive-resume/commit/00a972155) * Added an end-to-end Application Tracker test covering the main application workflow. [af751e4f](https://github.com/amruthpillai/reactive-resume/commit/af751e4f) ## Import & Export * Added Markdown export support for resumes, powered by new shared resume-section and Markdown helpers so exports preserve the resume's core structure in a portable text format. [20c803e93](https://github.com/amruthpillai/reactive-resume/commit/20c803e93) * Split resume and cover-letter download behavior so each export path uses the right file and filename. [20c803e93](https://github.com/amruthpillai/reactive-resume/commit/20c803e93) * Updated PDF download URL handling and export tests for the new download dialog. [20c803e93](https://github.com/amruthpillai/reactive-resume/commit/20c803e93) ## Documentation * Added guides for tracking job applications and importing applications from CSV, including screenshots and troubleshooting notes. [540796cd6](https://github.com/amruthpillai/reactive-resume/commit/540796cd6) * Refreshed the resume export and cover-letter guides to match the new download flow. [be43b455](https://github.com/amruthpillai/reactive-resume/commit/be43b455) ## Reliability & Performance * Improved Application Tracker rendering, tile colors, file-attachment handling, and dashboard responsiveness. [00a972155](https://github.com/amruthpillai/reactive-resume/commit/00a972155) * Cut builder per-keystroke render cost by tightening the builder header, dock, design panel, and section form updates. [5c75147d](https://github.com/amruthpillai/reactive-resume/commit/5c75147d) * Improved mobile layouts across the agent pages, builder header, dashboard resume list, and dashboard resume grid. [8416a921](https://github.com/amruthpillai/reactive-resume/commit/8416a921) * Eliminated layout shift from the homepage hero video by reserving its rendered space. [be1acbc2](https://github.com/amruthpillai/reactive-resume/commit/be1acbc2) * Fixed server-side rendering for auth email templates by importing React where the template runtime needs it. [af751e4f](https://github.com/amruthpillai/reactive-resume/commit/af751e4f) ## Self-Hosting & Maintenance * Added the Better Auth two-factor schema migration. [9f9268f3](https://github.com/amruthpillai/reactive-resume/commit/9f9268f3) * Added design-sync inputs and preview files for Reactive Resume UI components. [a28e3baa](https://github.com/amruthpillai/reactive-resume/commit/a28e3baa), [6e7fc680](https://github.com/amruthpillai/reactive-resume/commit/6e7fc680) * Synced translation catalogs for the new Application Tracking and export copy. [e99c1665](https://github.com/amruthpillai/reactive-resume/commit/e99c1665), [0d1bfd4e](https://github.com/amruthpillai/reactive-resume/commit/0d1bfd4e) * Addressed React Doctor findings, cleaned up Knip issues, updated dependencies, and refreshed TypeScript native preview versions. [5a1cc658](https://github.com/amruthpillai/reactive-resume/commit/5a1cc658), [5c1845b1](https://github.com/amruthpillai/reactive-resume/commit/5c1845b1), [91b4c1e6](https://github.com/amruthpillai/reactive-resume/commit/91b4c1e6) **Full Changelog**: [v5.2.0...v5.2.1](https://github.com/amruthpillai/reactive-resume/compare/v5.2.0...v5.2.1) ## Highlights * **Undo and redo across the builder.** Every change — typing, drag-and-drop, template and layout switches — can now be undone and redone with `Cmd/Ctrl+Z` and `Cmd/Ctrl+Shift+Z`, or the new toolbar buttons. Rapid typing collapses into a single step, so undo feels natural. [b044b6cc](https://github.com/amruthpillai/reactive-resume/commit/b044b6cc) * **Version history with one-click restore.** Reactive Resume now snapshots your resume at key moments — template switches, imports, AI edits, and periodic saves — and a new clock menu in the builder header lets you restore any earlier version. Restoring is non-destructive: it's just another change you can roll back. [b044b6cc](https://github.com/amruthpillai/reactive-resume/commit/b044b6cc) * **An AI assistant built into the builder.** A new Sparkle button opens the AI assistant as a side panel next to your resume, so you can chat about the resume you're editing and apply changes inline without leaving the builder. Its edits show up live and are captured in version history. [a1562aaa](https://github.com/amruthpillai/reactive-resume/commit/a1562aaa) * **A real mobile and tablet builder.** On phones and small tablets the builder now uses a full-screen layout with an Edit / Preview / Design tab bar, instead of a cramped three-panel desktop layout squeezed onto a small screen. [d933624a](https://github.com/amruthpillai/reactive-resume/commit/d933624a) * **Preview any template with your own content.** Hovering a template — both the current-template card and every tile in the template gallery — now renders a live preview built from your actual resume data, so you can compare templates with your content before switching. [9d742f78](https://github.com/amruthpillai/reactive-resume/commit/9d742f78) * **Polished motion across the app.** Menus, dialogs, tooltips, tabs, buttons, sheets, and form validation now share a consistent motion system with interruptible transitions and cleaner press feedback, so the builder and dashboard feel smoother end to end. [578a9832](https://github.com/amruthpillai/reactive-resume/commit/578a9832) ## Resume Builder * **Control page breaks per section.** New **Keep together** and **Start on new page** options let you decide whether a section can split across pages or begins on a fresh one in the exported PDF. [155a7b27](https://github.com/amruthpillai/reactive-resume/commit/155a7b27) * **Move sections between pages and columns from a menu.** The layout panel now has a **Move to** menu, so you can relocate a section without dragging. [02e1aff7](https://github.com/amruthpillai/reactive-resume/commit/02e1aff7) * **Crop and zoom your profile picture.** Choosing a picture now opens a crop step with a zoom slider and drag-to-reposition before it uploads. [f4bc3e7c](https://github.com/amruthpillai/reactive-resume/commit/f4bc3e7c), [f855af47](https://github.com/amruthpillai/reactive-resume/commit/f855af47) * **Better zoom and page controls** in the preview: a live zoom-percentage readout with Fit and 100% options, and `Cmd+0` to reset. [9c5b182a](https://github.com/amruthpillai/reactive-resume/commit/9c5b182a) * **A primary Download button in the header**, with a menu for PDF, DOCX, JSON, and Print. [446c1843](https://github.com/amruthpillai/reactive-resume/commit/446c1843) * **Section rail navigation** now scrolls to and highlights the section you pick, with proper tooltips and labels. [9bf606ae](https://github.com/amruthpillai/reactive-resume/commit/9bf606ae) * **Autosave status and safer collaborative editing.** The header shows a Saving / Saved indicator; a locked resume is read-only everywhere in the builder; and changes from another tab or the AI agent are announced and no longer overwrite the field you're actively typing in. [b082bb9f](https://github.com/amruthpillai/reactive-resume/commit/b082bb9f) * A live character counter and a tidier toolbar in the rich-text editor. [fa4ca06e](https://github.com/amruthpillai/reactive-resume/commit/fa4ca06e) ## AI Assistant * **Embedded AI assistant panel** in the builder, scoped to the open resume and reusing the full agent chat, so edits apply to the resume in front of you. Requires a configured AI provider. [a1562aaa](https://github.com/amruthpillai/reactive-resume/commit/a1562aaa) * **Simpler AI provider setup.** Provider settings now use a staged form — provider and API key first, advanced options collapsed — and test the connection automatically when you save. [454ccc59](https://github.com/amruthpillai/reactive-resume/commit/454ccc59) * **Richer assistant replies.** Agent chat now renders GitHub-flavored Markdown, so tables in the assistant's responses display as real tables instead of raw text. [82d96124](https://github.com/amruthpillai/reactive-resume/commit/82d96124) * **More reliable agent edits to sections.** The agent now targets built-in sections (`/sections/...`) and custom sections (`/customSections/...`) with the correct paths, and section-shortcut paths are normalized before a patch is applied, so edits to experience, education, and custom sections land where you expect. [82d96124](https://github.com/amruthpillai/reactive-resume/commit/82d96124) ## Dashboard & Navigation * **You now land in the builder right after creating a resume**, instead of being returned to the dashboard. [49f2c93f](https://github.com/amruthpillai/reactive-resume/commit/49f2c93f) * **Search your resumes** from the dashboard once you have more than a few. [fa4ca06e](https://github.com/amruthpillai/reactive-resume/commit/fa4ca06e) * **Command palette discoverability**: a Search button with a `⌘K` hint in the dashboard sidebar. [d10a7e5f](https://github.com/amruthpillai/reactive-resume/commit/d10a7e5f) * The Create and Import cards collapse into compact header buttons once you have resumes. [fa4ca06e](https://github.com/amruthpillai/reactive-resume/commit/fa4ca06e) * Fixed the command palette resume list so it reliably shows your resumes, sorted by most recently updated. [82d96124](https://github.com/amruthpillai/reactive-resume/commit/82d96124) ## Statistics * **Views and downloads trends.** Each statistics card now shows a 30-day sparkline and how it compares to the previous period. [66ee23ee](https://github.com/amruthpillai/reactive-resume/commit/66ee23ee) ## Public Sharing * **A proper public resume page** with an identity header (name, headline, and picture), a clear primary download action, and per-resume social / Open Graph previews, so shared links look right on LinkedIn, Slack, and iMessage. [f53d2b86](https://github.com/amruthpillai/reactive-resume/commit/f53d2b86) ## Accessibility & Internationalization * **Screen-reader access to the live preview.** The PDF preview now includes a hidden, structured text version of your resume so assistive technology can read it. [b76eb602](https://github.com/amruthpillai/reactive-resume/commit/b76eb602) * **Landmarks, skip links, and accessible names** across the builder and dashboard, and labels for the icon-only buttons that were previously unnamed to screen readers. [d10a7e5f](https://github.com/amruthpillai/reactive-resume/commit/d10a7e5f), [82bd14e3](https://github.com/amruthpillai/reactive-resume/commit/82bd14e3), [c67f84fc](https://github.com/amruthpillai/reactive-resume/commit/c67f84fc) * **A searchable language picker** (by English name, native name, or ISO code) and correct handling of mixed left-to-right and right-to-left text. [a41197ed](https://github.com/amruthpillai/reactive-resume/commit/a41197ed) ## Settings & Data * **Export all of your data** from the Danger Zone. [6d774cbc](https://github.com/amruthpillai/reactive-resume/commit/6d774cbc) * **Email-verification prompts are hidden when no mail server is configured**, so self-hosted instances without SMTP don't nag you to verify. [c7f77570](https://github.com/amruthpillai/reactive-resume/commit/c7f77570) ## Import & Export * **File-first import with auto-detection.** Pick a file and Reactive Resume detects the format; AI-based imports check for a configured provider up front. [e586a78e](https://github.com/amruthpillai/reactive-resume/commit/e586a78e) ## Reliability & Fixes * Made concurrent resume writes safe by wrapping patch and statistics updates in database transactions, and fixed a version-history double-snapshot. [b3f4a194](https://github.com/amruthpillai/reactive-resume/commit/b3f4a194) * Fixed a live-preview memory leak (image blobs weren't released) and serialized preview renders so they don't stack up. [f005be78](https://github.com/amruthpillai/reactive-resume/commit/f005be78) * Public link previews now show your name instead of a generic "Resume" placeholder. [4da7a2e0](https://github.com/amruthpillai/reactive-resume/commit/4da7a2e0) * Fixed the first-paint loading shell so the app reliably mounts. [47465fbb](https://github.com/amruthpillai/reactive-resume/commit/47465fbb) * Used the compact brand icon on the first-paint and loading screens for a cleaner startup. [82d96124](https://github.com/amruthpillai/reactive-resume/commit/82d96124) * **PDF list rendering fixes**: bullet alignment and margins, nested list layout, page breaks that keep the marker with its item, and text that continues after a line break. [#3202](https://github.com/amruthpillai/reactive-resume/pull/3202), [#3198](https://github.com/amruthpillai/reactive-resume/pull/3198), [#3178](https://github.com/amruthpillai/reactive-resume/pull/3178), [#3186](https://github.com/amruthpillai/reactive-resume/pull/3186) * Kept the server running through transient Postgres disconnects (for example, idle drops from serverless Postgres providers like Neon) by handling database pool errors and reconnecting on the next query. Thanks to [@helder-mattos](https://github.com/helder-mattos). [#3172](https://github.com/amruthpillai/reactive-resume/pull/3172) * Fixed the Atlas Cloud sponsor logo so the whole logo reliably opens the sponsor site in a new tab. [#3170](https://github.com/amruthpillai/reactive-resume/pull/3170) ## Localization & Maintenance * Synced the latest translation catalogs from Crowdin. [#3167](https://github.com/amruthpillai/reactive-resume/pull/3167), [#3183](https://github.com/amruthpillai/reactive-resume/pull/3183) * Added a Playwright end-to-end test setup, removed dead code and unused exports, and refreshed workspace dependencies. [dfd2c77b](https://github.com/amruthpillai/reactive-resume/commit/dfd2c77b), [a4999c04](https://github.com/amruthpillai/reactive-resume/commit/a4999c04) **Full Changelog**: [v5.1.9...v5.2.0](https://github.com/amruthpillai/reactive-resume/compare/v5.1.9...v5.2.0) ## Highlights * **Better multilingual PDF rendering.** PDF generation now uses script-aware Noto fallback stacks for Korean, Japanese, Traditional and Simplified Chinese, Arabic, Hebrew, and Thai, so non-Latin resumes render more reliably in the live preview and exported PDFs. [#3158](https://github.com/amruthpillai/reactive-resume/pull/3158) * **Hide Link Underline setting.** Resume page settings now include a dedicated **Hide Link Underline** option that is saved with the resume and respected by PDF templates. [5fb4976ec](https://github.com/amruthpillai/reactive-resume/commit/5fb4976ec), [#3134](https://github.com/amruthpillai/reactive-resume/issues/3134) * **Sponsor placements.** The landing page and docs now include optional sponsor placements for Atlas Cloud, controlled by a new feature flag so deployments can opt in when appropriate. [f14d8ce69](https://github.com/amruthpillai/reactive-resume/commit/f14d8ce69) ## Resume Builder & Rendering * Added the **Hide Link Underline** page option to the builder, resume schema, default resume data, import path, and shared PDF link rendering. [5fb4976ec](https://github.com/amruthpillai/reactive-resume/commit/5fb4976ec), [90a9bb9cf](https://github.com/amruthpillai/reactive-resume/commit/90a9bb9cf), [#3134](https://github.com/amruthpillai/reactive-resume/issues/3134) * Fixed mixed CJK and Latin word wrapping so CJK text can still break per character without splitting Latin words letter by letter. [#3136](https://github.com/amruthpillai/reactive-resume/pull/3136) * Added locale and content-aware PDF fallback fonts for Korean, Japanese, Chinese, Arabic, Hebrew, and Thai, while keeping CJK-specific line breaking limited to CJK scripts. [#3158](https://github.com/amruthpillai/reactive-resume/pull/3158) * Fixed redacted resume access checks so placeholder resume data uses a non-empty name. [#3138](https://github.com/amruthpillai/reactive-resume/pull/3138) ## AI, MCP & Self-Hosting * Fixed AI resume analysis when model responses wrap JSON in Markdown code fences. [#3142](https://github.com/amruthpillai/reactive-resume/pull/3142) * Added `FLAG_DISABLE_API_RATE_LIMIT` for trusted self-hosted deployments that need to disable authentication API rate limiting, and documented it in the Docker self-hosting guide. [#3149](https://github.com/amruthpillai/reactive-resume/pull/3149) * Added `FLAG_SHOW_SPONSORS`, sponsor assets, landing-page placement, docs navigation, and README sponsor information for Atlas Cloud. [f14d8ce69](https://github.com/amruthpillai/reactive-resume/commit/f14d8ce69) * Fixed the MCP PDF download test mock to match the current tool behavior. [#3144](https://github.com/amruthpillai/reactive-resume/pull/3144) ## Localization & Maintenance * Synced translation catalogs from Crowdin across the app. [#3132](https://github.com/amruthpillai/reactive-resume/pull/3132), [#3135](https://github.com/amruthpillai/reactive-resume/pull/3135), [#3148](https://github.com/amruthpillai/reactive-resume/pull/3148), [#3162](https://github.com/amruthpillai/reactive-resume/pull/3162) * Updated workspace dependencies and refreshed linting/tooling configuration. [042d076ef](https://github.com/amruthpillai/reactive-resume/commit/042d076ef), [37faf592b](https://github.com/amruthpillai/reactive-resume/commit/37faf592b), [ef5ff30b](https://github.com/amruthpillai/reactive-resume/commit/ef5ff30b) **Full Changelog**: [v5.1.8...v5.1.9](https://github.com/amruthpillai/reactive-resume/compare/v5.1.8...v5.1.9) ## Highlights * **Section heading icons for PDF templates.** Resume section titles can now show customizable Phosphor icons in PDF output. Pick icons from the builder, hide individual section icons, or use the new page setting to hide heading icons separately from item-level icons. [b932711f0](https://github.com/amruthpillai/reactive-resume/commit/b932711f0) * **Multicolor text highlights.** The rich text editor now includes a highlight color picker with presets and custom colors. Dark highlights automatically switch marked text to white for readability, and highlight colors carry through PDF and DOCX exports. [e96a51f31](https://github.com/amruthpillai/reactive-resume/commit/e96a51f31) * **MCP PDF downloads.** MCP clients can now create short-lived authenticated PDF download URLs for resumes, making agent workflows able to retrieve generated PDF exports directly. [0df7f2113](https://github.com/amruthpillai/reactive-resume/commit/0df7f2113) ## Resume Builder & Editing * Added per-section icon pickers for summary, built-in sections, and custom section dialogs, with sensible default icons for existing resumes and a `"none"` option for hiding a specific section icon. [b932711f0](https://github.com/amruthpillai/reactive-resume/commit/b932711f0) * Added a **Hide Section Icons** page option and clarified the existing **Hide Icons** setting so section heading icons and item-level icons can be controlled independently. [b932711f0](https://github.com/amruthpillai/reactive-resume/commit/b932711f0) * Replaced the single-color rich text highlight toggle with a full highlight color picker, including preset colors, custom colors, and a clear action. [e96a51f31](https://github.com/amruthpillai/reactive-resume/commit/e96a51f31) * Synced new builder, section icon, and rich text editor labels across locale catalogs. [b932711f0](https://github.com/amruthpillai/reactive-resume/commit/b932711f0), [1507d869c](https://github.com/amruthpillai/reactive-resume/commit/1507d869c), [e96a51f31](https://github.com/amruthpillai/reactive-resume/commit/e96a51f31) ## Resume Rendering & Exports * Added section heading icon rendering to shared PDF templates, including heading-size scaling, default icon fallbacks for legacy resume data, and support for custom sections. [b932711f0](https://github.com/amruthpillai/reactive-resume/commit/b932711f0) * Preserved custom highlight colors in PDF and DOCX exports, including automatic white text on dark highlight colors. [e96a51f31](https://github.com/amruthpillai/reactive-resume/commit/e96a51f31) * Fixed experience entries with role progression so the main position and period still render in the header without repeating the period below it. [9ce5bacd2](https://github.com/amruthpillai/reactive-resume/commit/9ce5bacd2) * Fixed Custom Styles font size rules for resume icons and level indicators so those values affect actual icon dimensions in PDFs and builder previews. [1414fecad](https://github.com/amruthpillai/reactive-resume/commit/1414fecad), [e00ff8cec](https://github.com/amruthpillai/reactive-resume/commit/e00ff8cec) * Fixed the Glalie template contact-list border so it stays square instead of inheriting the picture border radius. [c1d11236a](https://github.com/amruthpillai/reactive-resume/commit/c1d11236a) ## MCP, API & Maintenance * Added the `download_resume_pdf` MCP tool, returning a signed PDF download URL that expires after 10 minutes. [0df7f2113](https://github.com/amruthpillai/reactive-resume/commit/0df7f2113) * Added the authenticated `/api/resumes/:id/pdf` download route used by MCP PDF downloads, with no-store caching, token validation, ownership checks, and safer PDF generation errors. [0df7f2113](https://github.com/amruthpillai/reactive-resume/commit/0df7f2113), [a8c70d784](https://github.com/amruthpillai/reactive-resume/commit/a8c70d784), [152279473](https://github.com/amruthpillai/reactive-resume/commit/152279473) * Made MCP server cards, OpenAPI output, schema JSON, and server metadata use runtime-safe app version handling in development. [d09ad2cdc](https://github.com/amruthpillai/reactive-resume/commit/d09ad2cdc) * Updated the release Docker workflow to purge Cloudflare cache after publishing a release image, so cached release artifacts refresh after deployment. [6852f586e](https://github.com/amruthpillai/reactive-resume/commit/6852f586e) **Full Changelog**: [v5.1.7...v5.1.8](https://github.com/amruthpillai/reactive-resume/compare/v5.1.7...v5.1.8) ## Highlights * **Custom Styles replaces Custom CSS.** Reactive Resume now has a structured Custom Styles panel in the builder for fine-grained resume styling without raw CSS. Because v5 renders resumes through React PDF instead of browser HTML/CSS, Custom Styles uses safe, semantic rules that work consistently in the live preview, exported PDFs, public resumes, and server-side generation. [b04eef147](https://github.com/amruthpillai/reactive-resume/commit/b04eef147), [c6a654191](https://github.com/amruthpillai/reactive-resume/commit/c6a654191), [16f4d2c07](https://github.com/amruthpillai/reactive-resume/commit/16f4d2c07) Custom Styles section in the right sidebar with target scope, style slot, style controls, and applied rules * **Better live resume sync.** The builder now handles local edits, Agent updates, MCP changes, and API updates more reliably by saving the latest resume draft and merging server metadata without losing in-progress changes. [dd1e37e57](https://github.com/amruthpillai/reactive-resume/commit/dd1e37e57) * **More accessible links across the app and exports.** Link handling was refreshed across web UI, dialogs, PDF preview/rendering, email, and shared UI components for improved accessibility behavior. [8da780c86](https://github.com/amruthpillai/reactive-resume/commit/8da780c86) ## Custom Styles * Added a new **Custom Styles** section to the builder's right sidebar with target scope, style slot, style controls, and applied-rule management. [b04eef147](https://github.com/amruthpillai/reactive-resume/commit/b04eef147), [c6a654191](https://github.com/amruthpillai/reactive-resume/commit/c6a654191) * Added style rule metadata to resume data so styling can be saved with the resume and preserved during imports from Reactive Resume v4 JSON. [b04eef147](https://github.com/amruthpillai/reactive-resume/commit/b04eef147) * Added target scopes for **All sections**, **Section type**, and **Specific section**, allowing broad defaults or precise overrides for duplicate and custom sections. [b04eef147](https://github.com/amruthpillai/reactive-resume/commit/b04eef147) * Added semantic style slots for section containers, headings, item containers, primary and secondary text, links, icons, level indicators, rich-text paragraphs, lists, list rows, list content, inline links, bold text, and highlights. [b04eef147](https://github.com/amruthpillai/reactive-resume/commit/b04eef147), [c6a654191](https://github.com/amruthpillai/reactive-resume/commit/c6a654191) * Added structured controls for color, typography, spacing, borders, opacity, text decoration, alignment, and transforms, with empty fields falling back to the selected template. [b04eef147](https://github.com/amruthpillai/reactive-resume/commit/b04eef147) * Added shared PDF style-rule resolution so Custom Styles layer on top of every template and apply consistently to rich text, lists, contact items, level indicators, and template-owned section rendering. [b04eef147](https://github.com/amruthpillai/reactive-resume/commit/b04eef147), [c6a654191](https://github.com/amruthpillai/reactive-resume/commit/c6a654191) * Added focused tests for style rule schema validation, PDF style resolution, rich-text style inheritance, and the Custom Styles builder UI. [b04eef147](https://github.com/amruthpillai/reactive-resume/commit/b04eef147), [c6a654191](https://github.com/amruthpillai/reactive-resume/commit/c6a654191) ## Builder, Accessibility & Agent Updates * Reworked resume draft saving so the builder queues full draft saves, retries failed saves, and avoids overwriting newer local edits when server responses arrive out of order. [dd1e37e57](https://github.com/amruthpillai/reactive-resume/commit/dd1e37e57) * Added a resume update subscription for Agent threads so resume previews can refresh when external Agent changes land. [dd1e37e57](https://github.com/amruthpillai/reactive-resume/commit/dd1e37e57) * Improved import, picture, information, resume analysis, homepage, Agent, and shared UI link behavior for better accessibility and safer rendering. [8da780c86](https://github.com/amruthpillai/reactive-resume/commit/8da780c86) * Added safer PDF text style handling for links and rich text so invalid or unsupported link styles do not leak into React PDF output. [8da780c86](https://github.com/amruthpillai/reactive-resume/commit/8da780c86) * Improved combobox behavior and tests used by Custom Styles and other builder controls. [c6a654191](https://github.com/amruthpillai/reactive-resume/commit/c6a654191), [b49158263](https://github.com/amruthpillai/reactive-resume/commit/b49158263) ## Docs, Localization & Maintenance * Added a full **Using Custom Styles** guide with screenshots, target-scope guidance, style-slot reference tables, practical examples, and notes on when to use Custom Styles instead of the broader Design, Typography, Layout, and Page settings. [16f4d2c07](https://github.com/amruthpillai/reactive-resume/commit/16f4d2c07) * Added an architecture decision record explaining why structured Style Rules are the supported replacement for raw Custom CSS in the React PDF rendering model. [b04eef147](https://github.com/amruthpillai/reactive-resume/commit/b04eef147) * Added a Custom Styles header-target design note for future styling scope decisions. [7bff6644d](https://github.com/amruthpillai/reactive-resume/commit/7bff6644d) * Synced missing translations for Custom Styles and related builder text across locale catalogs. [b49158263](https://github.com/amruthpillai/reactive-resume/commit/b49158263) * Removed React Doctor from package scripts, refreshed task dependencies in `turbo.json`, and cleaned up related workspace dependency entries. [8461aa65](https://github.com/amruthpillai/reactive-resume/commit/8461aa65) **Full Changelog**: [v5.1.6...v5.1.7](https://github.com/amruthpillai/reactive-resume/compare/v5.1.6...v5.1.7) ## Highlights * **Right-to-left PDF support across all templates.** Resumes in RTL locales now mirror layout, alignment, and rich text direction consistently across every PDF template, not just Rhyhorn. [24c882fa9](https://github.com/amruthpillai/reactive-resume/commit/24c882fa9), [266bc291e](https://github.com/amruthpillai/reactive-resume/commit/266bc291e) * **More reliable social login for upgraded accounts.** OAuth sign-in now reconciles existing email-based accounts with legacy GitHub-linked profiles, so migrated users can sign back in without creating duplicate accounts. [86fff7237](https://github.com/amruthpillai/reactive-resume/commit/86fff7237) ## Resume Rendering & Exports * Added shared RTL layout helpers and a single `rtl` flag on the PDF render provider, then migrated every template page to mirrored layout styles. [24c882fa9](https://github.com/amruthpillai/reactive-resume/commit/24c882fa9) * Fixed plain rich text rendering in PDFs by routing paragraph content through dedicated `PdfText` renderers. [24c882fa9](https://github.com/amruthpillai/reactive-resume/commit/24c882fa9) * Mapped legacy `Times New Roman` font selections to the PDF-compatible `Times-Roman` family so older resumes keep rendering correctly. [24c882fa9](https://github.com/amruthpillai/reactive-resume/commit/24c882fa9) * Reduced the default vertical gap between list items in PDF templates for tighter, more readable bullet and numbered lists. [17cddbad6](https://github.com/amruthpillai/reactive-resume/commit/17cddbad6) * Fixed color parsing for 3-digit hex values such as `#abc`, which previously failed to convert correctly in the builder. [273e17c0d](https://github.com/amruthpillai/reactive-resume/commit/273e17c0d) ## Authentication * Added OAuth profile reconciliation that matches returning users by normalized email and legacy GitHub username/display name before creating a new account. [86fff7237](https://github.com/amruthpillai/reactive-resume/commit/86fff7237) ## AI & Agent Workflows * Fixed Agent thread deletion to remove attachments and mark the thread deleted before storage cleanup, preventing inconsistent database state when storage cleanup fails partway through. [7557ab13a](https://github.com/amruthpillai/reactive-resume/commit/7557ab13a) ## Docs & Maintenance * Updated the Docker quick-start guide to use a shallow clone for faster setup. Thanks to [@umairkhurshid](https://github.com/umairkhurshid). [75e944613](https://github.com/amruthpillai/reactive-resume/commit/75e944613) * Centralized RTL locale detection in `@reactive-resume/utils/locale` and removed duplicate web-side helpers. [c66560ee1](https://github.com/amruthpillai/reactive-resume/commit/c66560ee1) * Ran React Doctor lint passes, refreshed translations, and added dynamic imports where appropriate. [39e88dd36](https://github.com/amruthpillai/reactive-resume/commit/39e88dd36) * Updated workspace dependencies. [3596102c6](https://github.com/amruthpillai/reactive-resume/commit/3596102c6), [6ec4da791](https://github.com/amruthpillai/reactive-resume/commit/6ec4da791), [7eea6675c](https://github.com/amruthpillai/reactive-resume/commit/7eea6675c) **Full Changelog**: [v5.1.5...v5.1.6](https://github.com/amruthpillai/reactive-resume/compare/v5.1.5...v5.1.6) **Self-hosters, please review your environment before upgrading.** The production image now runs a dedicated Hono server from `apps/server/dist/index.mjs`. Remove `OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS`, `CLOUDFLARE_ACCOUNT_ID`, and `CLOUDFLARE_API_TOKEN` from your environment if they are still set. Local development now uses `PORT=3000` for Vite and `SERVER_PORT=3001` for the Hono server. This should not affect production deployments. ## Highlights * **Dedicated Hono server runtime.** Reactive Resume now builds a separate `apps/server` app that mounts auth, RPC, MCP, OpenAPI, uploads, schema JSON, SEO endpoints, health checks, and the built web app from one Node.js process. [ecc1fd9a8](https://github.com/amruthpillai/reactive-resume/commit/ecc1fd9a8), [9033da082](https://github.com/amruthpillai/reactive-resume/commit/9033da082) * **Clearer self-hosting runtime model.** The Docker image now builds both `web` and `server`, runs `node apps/server/dist/index.mjs`, and keeps `/api/health` pointed at the production server port. [ecc1fd9a8](https://github.com/amruthpillai/reactive-resume/commit/ecc1fd9a8) * **Safer Agent restore behavior.** Agent edits now store a resume snapshot before applying a patch, so restoring an action can roll the draft back to the exact prior state and mark later agent patches as rolled back. [d961e6535](https://github.com/amruthpillai/reactive-resume/commit/d961e6535) ## Self-Hosting & Environment * Added `SERVER_PORT` for local development. Vite serves the web app on `PORT` and proxies API, MCP, upload, well-known, and schema routes to the Hono server on `SERVER_PORT`. * Updated the production Dockerfile to copy `apps/web/dist`, `apps/server/dist`, server package dependencies, and migrations into the runtime image. The production start command is now `node apps/server/dist/index.mjs`. * Updated `compose.yml` to use the published image by default and load app configuration through `.env` instead of embedding the main app environment block inline. * Updated `compose.dev.yml` to expose both `3000` and `3001`, add an app profile, and health-check the Hono server port. * Startup checks now run from the server process, including database migrations and local storage writability validation when S3-compatible storage is not configured. * Removed `OAUTH_DYNAMIC_CLIENT_REDIRECT_HOSTS`. Dynamic OAuth client registration now allows the app origin and loopback callbacks by default. * Added `FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI` for trusted self-hosted deployments that intentionally need arbitrary redirect URIs, including custom schemes, private hosts, or non-loopback `http://` callbacks. Keep this disabled on public or multi-tenant instances. [445359ebe](https://github.com/amruthpillai/reactive-resume/commit/445359ebe) * Removed the documented `BETTER_AUTH_URL` and `BETTER_AUTH_SECRET` override path. Auth metadata, JWKS, and OAuth callback URLs are now derived from `APP_URL` and `AUTH_SECRET`. * Removed Cloudflare URL extraction environment variables. Live Agent web research now depends on the selected AI provider and model supporting native web search. * Renamed the Crowdin token example from `CROWDIN_PERSONAL_TOKEN` to `CROWDIN_API_TOKEN`. ## App Runtime & Architecture * Moved API/auth/MCP/OpenAPI/static route ownership out of the web app and into `apps/server`. * Changed the web app build to a Vite/TanStack Router SPA output under `apps/web/dist`, with the Hono server serving the built app and static fallback responses. * Added `robots.txt`, `sitemap.xml`, `llms.txt`, structured data helpers, and server-owned SEO responses. [8fcf0ec64](https://github.com/amruthpillai/reactive-resume/commit/8fcf0ec64) * Added package-boundary rules to Turborepo and per-workspace `turbo.json` files to enforce browser, server, domain, adapter, and infra ownership. * Split focused domains into new packages: `@reactive-resume/docx`, `@reactive-resume/mcp`, and `@reactive-resume/resume`. * Moved development-only scripts from `packages/scripts` to `tooling` so workspace packages contain app/runtime code rather than private repo tooling. * Reorganized API implementation into feature-owned modules under `packages/api/src/features/*`. ## AI & Agent Workflows * Replaced stored inverse JSON patches with `snapshot_data` on agent actions. Legacy actions without snapshots remain non-restorable. * Added a migration that adds `agent_actions.snapshot_data` and drops `agent_actions.inverse_operations`. * Updated Agent UI and docs from "Revert" language to "Restore" language to clarify that restoring an older action rolls back that action and later applied agent patches. * Updated Agent tool documentation to describe provider-native `web_search` behavior instead of app-owned URL fetching. * Kept unsafe/private AI provider base URLs behind `FLAG_ALLOW_UNSAFE_AI_BASE_URL`, with public HTTPS provider URLs remaining the default safe path. ## Resume Rendering & Exports * Moved browser PDF preview code into `apps/web/src/features/resume/preview` and public resume viewer code into `apps/web/src/features/resume/public`. * Added direct PDF.js canvas preview and thumbnail rendering through legacy PDF.js entrypoints, with tests that prevent browser preview code from importing the modern PDF.js runtime. [7cade6980](https://github.com/amruthpillai/reactive-resume/commit/7cade6980) * Added explicit `@reactive-resume/pdf/browser` and `@reactive-resume/pdf/server` generation adapters. * Simplified shared sidebar summary handling for PDF templates and added focused coverage for featured summary behavior. [17f351171](https://github.com/amruthpillai/reactive-resume/commit/17f351171) ## Docs & Maintenance * Added new use-case docs for free, open-source, self-hosted, privacy-focused, export/share, AI, and API/MCP resume workflows. * Rewrote contributor architecture docs around the new monorepo runtime, package ownership model, and boundary checks. * Updated self-hosting Docker and SSO docs for the Hono runtime, removed environment variables, OAuth redirect safety, provider-native Agent web research, and local development ports. * Added and updated architecture notes, plans, and specs for the Hono migration, monorepo reorganization, Docker tagging, manifest-only PWA behavior, unsafe OAuth redirect policy, and Agent snapshot restore design. * Updated Knip configuration so server runtime dependencies that are imported by the built server bundle are treated as intentional dependencies. **Full Changelog**: [v5.1.4...v5.1.5](https://github.com/amruthpillai/reactive-resume/compare/v5.1.4...v5.1.5) **Self-hosters using AI features:** saved AI providers now require `ENCRYPTION_SECRET`, and the new AI Agent workspace also requires `REDIS_URL`. Agent attachments require S3-compatible storage for private objects; local filesystem storage still works for the rest of the app, but rejects private agent attachments. ## Highlights * **New AI Agent workspace.** Added a dedicated full-screen Agent workspace for working on isolated AI draft copies of resumes. Threads include a sidebar, chat, tool activity, file attachments, and a read-only resume preview with PDF download support. [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062) AI Agent workspace showing thread sidebar, chat, and resume preview * **Reviewable and reversible agent edits.** Agent-applied resume patches now appear as expandable tool activity, with raw JSON Patch details, operation summaries, revert support, and clear conflict handling when the resume has changed. [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062) AI Agent chat showing an applied patch with raw JSON details * **Public resumes now render with PDF.js.** Public resume pages now use the PDF.js-based viewer path, improving parity between the public page, builder preview, and exported PDF. [#3061](https://github.com/amruthpillai/reactive-resume/pull/3061) ## AI & Agent Workflows * Added server-side AI provider management with encrypted credentials, provider testing, and provider/model capability checks. This replaces the old local AI store and keeps AI configuration centralized. [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062) * Added Agent tools for reading resume drafts, using provider-native web search when supported, reading supported attachments, asking follow-up questions, and applying JSON Patch updates to the AI draft. [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062) * Added archive and delete actions for Agent threads, including read-only archived states, in-flight run cleanup when archiving, and ownership checks before destructive deletion. [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062) * Added attachment upload rate limits, private S3 ACLs for Agent attachments, runtime validation for streamed messages, transactional patch/action writes, and a unique message sequence index for safer Agent runs. [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062) * Added `FLAG_ALLOW_UNSAFE_AI_BASE_URL` for trusted self-hosted deployments that need private or local AI provider URLs, while still restricting provider URLs to `http` or `https`. Thanks to [@SirSKillz](https://github.com/SirSKillz). [#3059](https://github.com/amruthpillai/reactive-resume/pull/3059) ## Resume Rendering & Fonts * Restored legacy local font names from v5.0.x by mapping them to metric-compatible bundled web fonts, preventing upgraded resumes from unexpectedly changing line breaks, page counts, or overall layout. Thanks to [@JamesGoslings](https://github.com/JamesGoslings). [#3057](https://github.com/amruthpillai/reactive-resume/pull/3057) * Added metric-compatible aliases for `Times New Roman`, `Cambria`, `Arial`, `Garamond`, and `Calibri`, including Carlito as the Calibri-compatible target. [#3057](https://github.com/amruthpillai/reactive-resume/pull/3057) * Improved resume preview spacing normalization and added focused coverage for the public PDF viewer and preview helpers. [#3061](https://github.com/amruthpillai/reactive-resume/pull/3061), [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062) ## Self-Hosting, Docs & Maintenance * Added a development Dockerfile plus improved Compose development services and health checks for running Reactive Resume with local dependencies. [1294d3354](https://github.com/amruthpillai/reactive-resume/commit/1294d3354) * Updated self-hosting documentation for Redis, encrypted AI provider credentials, provider-native web research, private Agent attachments, S3 path-style storage, and unsafe AI base URL behavior. [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062), [#3059](https://github.com/amruthpillai/reactive-resume/pull/3059) * Added new and refreshed guides for the AI Agent workspace, Agent tools, AI setup, builder dock, dashboard management, importing, exporting, public sharing, and private notes. [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062), [affa1d664](https://github.com/amruthpillai/reactive-resume/commit/affa1d664) * Removed a stale Custom CSS documentation link now that custom CSS is no longer part of the v5.1 renderer flow. [#3056](https://github.com/amruthpillai/reactive-resume/pull/3056) * Added a Reactive Resume design system reference and updated dependencies across the workspace. [#3062](https://github.com/amruthpillai/reactive-resume/pull/3062) **Full Changelog**: [v5.1.3...v5.1.4](https://github.com/amruthpillai/reactive-resume/compare/v5.1.3...v5.1.4) ## Highlights * **New Scizor resume template.** Added the new **Scizor** layout to the template lineup, including builder support, schema/docs updates, and localization strings. [00dafd0c6](https://github.com/amruthpillai/reactive-resume/commit/00dafd0c6), [5f63dc876](https://github.com/amruthpillai/reactive-resume/commit/5f63dc876) Scizor template preview * **Smarter page settings in the builder.** Empty sections are now hidden from page settings to reduce noise and make layout management easier. [#3052](https://github.com/amruthpillai/reactive-resume/pull/3052) * **Faster, smoother preview loading.** Improved resume preview loading behavior and added focused tests for preview components. [92a0e3ddb](https://github.com/amruthpillai/reactive-resume/commit/92a0e3ddb) ## Resume Builder & PDF Export Fixes * Increased header name line height in PDF templates to prevent descender clipping. [#3050](https://github.com/amruthpillai/reactive-resume/pull/3050) * Improved CJK rendering reliability across PDF output, including better handling of hyphenation callbacks and italic fallback behavior. [62b0a1d53](https://github.com/amruthpillai/reactive-resume/commit/62b0a1d53), [83a407bc1](https://github.com/amruthpillai/reactive-resume/commit/83a407bc1), [33103536a](https://github.com/amruthpillai/reactive-resume/commit/33103536a), [64ac3ff32](https://github.com/amruthpillai/reactive-resume/commit/64ac3ff32) * Fixed split-row right-side content promotion behavior to preserve layout consistency in exports. [#3039](https://github.com/amruthpillai/reactive-resume/pull/3039) * Improved rich text and section data handling by filtering invalid or empty items and tightening schema validation for safer rendering. [334ea48bc](https://github.com/amruthpillai/reactive-resume/commit/334ea48bc), [0713cf20d](https://github.com/amruthpillai/reactive-resume/commit/0713cf20d), [4ebe9e5a6](https://github.com/amruthpillai/reactive-resume/commit/4ebe9e5a6) ## Quality, Docs & Maintenance * Expanded automated coverage significantly, including monorepo-wide unit/component tests and an additional \~500 tests across core packages. [6a01207b6](https://github.com/amruthpillai/reactive-resume/commit/6a01207b6), [#3038](https://github.com/amruthpillai/reactive-resume/pull/3038) * Migrated the test environment from jsdom to happy-dom for faster and more stable test runs. [7a60a42a0](https://github.com/amruthpillai/reactive-resume/commit/7a60a42a0) * Updated documentation and defaults, including AGENTS guidance and export format notes. [#3054](https://github.com/amruthpillai/reactive-resume/pull/3054), [71aadbd73](https://github.com/amruthpillai/reactive-resume/commit/71aadbd73), [a93e7bd19](https://github.com/amruthpillai/reactive-resume/pull/3024) * Synced translation catalogs from Crowdin and added template-specific translation updates for Scizor. [#3053](https://github.com/amruthpillai/reactive-resume/pull/3053), [e574d4005](https://github.com/amruthpillai/reactive-resume/pull/3037), [#3026](https://github.com/amruthpillai/reactive-resume/pull/3026), [#3023](https://github.com/amruthpillai/reactive-resume/pull/3023), [c5787fe15](https://github.com/amruthpillai/reactive-resume/commit/c5787fe15) * Updated dependencies and repository cleanup tasks, including PostCSS refresh and Knip fixes. [e35ff8391](https://github.com/amruthpillai/reactive-resume/commit/e35ff8391), [3cd228bd8](https://github.com/amruthpillai/reactive-resume/commit/3cd228bd8), [978cbaf1f](https://github.com/amruthpillai/reactive-resume/commit/978cbaf1f), [0daf868cd](https://github.com/amruthpillai/reactive-resume/commit/0daf868cd) **Full Changelog**: [v5.1.2...v5.1.3](https://github.com/amruthpillai/reactive-resume/compare/v5.1.2...v5.1.3) **Self-hosters using local storage:** the official Docker image now sets `LOCAL_STORAGE_PATH=/app/data` and validates that the directory is writable at startup. If you override the container environment, keep `LOCAL_STORAGE_PATH` pointed at an absolute writable path. ## Highlights * **AI Resume Assistant.** Added a chat window inside the resume builder for targeted resume edits. The assistant can draft JSON Patch proposals, show before/after previews, and lets you accept or reject each change before anything is applied. [#3022](https://github.com/amruthpillai/reactive-resume/pull/3022) * **Better CJK PDF output.** Added automatic CJK fallback font registration so Chinese, Japanese, and Korean text renders correctly in both the live PDF preview and exported PDFs. [#3016](https://github.com/amruthpillai/reactive-resume/pull/3016) ## Resume Builder & Exports * Added a builder dock shortcut for the AI assistant, with a draggable and resizable desktop window plus a mobile sheet layout. [#3022](https://github.com/amruthpillai/reactive-resume/pull/3022) * Added review controls for AI-generated proposals, including proposal queues, raw JSON Patch inspection, accept/reject actions, and stale-proposal handling when the resume changes. [#3022](https://github.com/amruthpillai/reactive-resume/pull/3022) * Fixed rich text PDF rendering when text blocks contain top-level inline content around lists or paragraphs. [42e83cc6](https://github.com/amruthpillai/reactive-resume/commit/42e83cc6) * Kept Latin-only PDF output unchanged while applying fallback fonts only when CJK glyphs are needed. [#3016](https://github.com/amruthpillai/reactive-resume/pull/3016) ## Sharing & Imports * Fixed public resume URLs returning a server error when the owner-only dashboard title was redacted to an empty string for viewers. [#3012](https://github.com/amruthpillai/reactive-resume/pull/3012) * Improved v4 JSON imports so custom section content, hidden items, and skill/language levels migrate correctly into v5 resumes. [#3013](https://github.com/amruthpillai/reactive-resume/pull/3013) ## Self-Hosting * Fixed Docker local-storage health checks by resolving the data directory through `LOCAL_STORAGE_PATH` instead of relying on the runtime working directory. [#3004](https://github.com/amruthpillai/reactive-resume/pull/3004) * Added startup validation for the local storage directory so misconfigured volume permissions fail early with a clearer error. [#3004](https://github.com/amruthpillai/reactive-resume/pull/3004) * Updated `.env.example`, the Dockerfile, Compose configuration, and Docker self-hosting docs for the new local storage path behavior. [#3004](https://github.com/amruthpillai/reactive-resume/pull/3004) ## Maintenance & Localization * Synced translation catalogs from Crowdin. [#3005](https://github.com/amruthpillai/reactive-resume/pull/3005) * Updated dependencies and lockfile entries needed for the AI assistant, PDF rich text normalization, and related test coverage. **Full Changelog**: [v5.1.1...v5.1.2](https://github.com/amruthpillai/reactive-resume/compare/v5.1.1...v5.1.2) ## Highlights * **Free-form resume pages.** Added a new **Free-form** page format for resumes that should keep A4 width while allowing content to flow beyond a fixed page height. This is useful for long-form web-style resumes while preserving predictable export sizing. [#2991](https://github.com/amruthpillai/reactive-resume/issues/2991) * **PDF downloads through the API.** Added an authenticated `GET /resumes/{id}/pdf` endpoint so API clients can generate and download a resume PDF directly. The OpenAPI spec has been updated with the new route. [5042ad9d](https://github.com/amruthpillai/reactive-resume/commit/5042ad9d) ## Resume Builder & Exports * Fixed nested lists in PDF rendering so rich text with sub-lists exports correctly. [#2993](https://github.com/amruthpillai/reactive-resume/issues/2993) * Fixed inline item links in exported PDFs and made resume links consistently underlined. [#2978](https://github.com/amruthpillai/reactive-resume/issues/2978) * Added italic font registration for PDF generation and falls back to **IBM Plex Serif** when a selected font is unavailable. [6d54ffa8](https://github.com/amruthpillai/reactive-resume/commit/6d54ffa8), [4c771307](https://github.com/amruthpillai/reactive-resume/commit/4c771307) * Improved header name line height across templates for cleaner PDF output. [#2976](https://github.com/amruthpillai/reactive-resume/issues/2976) * Added prose styles to the rich text editor so formatted content is easier to read while editing. [#2984](https://github.com/amruthpillai/reactive-resume/issues/2984) * Added a preview control to toggle page stacking and adjusted the default preview zoom for a better builder canvas experience. ## Fixes * Fixed a runtime error when enabling two-factor authentication. [#2981](https://github.com/amruthpillai/reactive-resume/issues/2981) * Fixed excessive re-renders in the Experience section when editing role progression. [#2983](https://github.com/amruthpillai/reactive-resume/issues/2983) * Removed route preloading to avoid unwanted route work while navigating the app. [#2949](https://github.com/amruthpillai/reactive-resume/issues/2949) * Relaxed resume data parsing to accept compatible objects with additional fields. [#2793](https://github.com/amruthpillai/reactive-resume/issues/2793) * Updated dialog layout behavior so tall dialogs scroll correctly on smaller screens. * Updated the sample resume picture URL to point to a valid bundled image. ## Self-Hosting * Automatically loads `.env` from the workspace root for server-side code, improving local and self-hosted configuration behavior. [#2987](https://github.com/amruthpillai/reactive-resume/issues/2987) * Restored the local storage path to `/app/data` in the official container image and clarified the Docker storage documentation. [#2990](https://github.com/amruthpillai/reactive-resume/issues/2990) ## Maintenance & Localization * Synced translation catalogs from Crowdin. [#2995](https://github.com/amruthpillai/reactive-resume/pull/2995), [#2997](https://github.com/amruthpillai/reactive-resume/pull/2997) * Removed unused dependencies, stale generated cache artifacts, and obsolete tests from the repository. **Full Changelog**: [v5.1.0...v5.1.1](https://github.com/amruthpillai/reactive-resume/compare/v5.1.0...v5.1.1) **Self-hosters, please read before upgrading.** * **No more Browserless / Chromium dependency.** From v5.1.0 onwards, you do **not** need to run a `printer`, Browserless, or headless Chrome service alongside Reactive Resume. PDF generation is now performed entirely in your browser via `@react-pdf/renderer`. The `BROWSERLESS_TOKEN`, `PRINTER_ENDPOINT`, `PRINTER_APP_URL`, and `FLAG_DEBUG_PRINTER` environment variables are no longer read and can be removed from your `.env`. * **Database migrations.** This release ships several new schema migrations to bring the resume model up to date. They run automatically on container start, but you should **back up your PostgreSQL database before upgrading** in case rollback is needed. * **Custom CSS has been removed.** Because the resume PDF is no longer produced by a headless browser, raw CSS no longer applies to the exported document. A first-class template-customization story is on the roadmap for a future release. * **Job Listings has been removed.** The JSearch/RapidAPI-backed job listings feature and its settings were removed in the v5.1.0 transition. The old job-search settings path now redirects to **Integrations**. To tailor a resume, paste a job description into the AI Agent; see [Using the AI Agent workspace](/guides/using-ai-agent#tailor-a-resume-to-a-supplied-job-description). ## Highlights * **PDF generation moved fully client-side.** `@react-pdf/renderer` now produces the exported PDF directly in your browser, and the in-builder live preview is rendered with `pdfjs`, so what you see in the preview is exactly what you'll download. * **All resume templates re-ported.** Azurill, Bronzor, Chikorita, Ditgar, Ditto, Gengar, Glalie, Kakuna, Lapras, Leafish, Meowth, Onyx, Pikachu, Rhyhorn, and Scizor have all been re-implemented on the new renderer with section-by-section parity. ## Resume Builder * **Pixel-accurate live preview.** The builder preview is now rendered with `pdfjs` against the same document tree used for export, eliminating the long-standing "looks fine in the preview but breaks in the PDF" class of bugs. * **TanStack Form everywhere.** All 35 form-bearing surfaces in the app — login, register, forgot-password, resume sections, settings, and dialogs — have been migrated to TanStack Form. `react-hook-form` and `@hookform/*` packages have been removed. * **TanStack Query is the single source of truth for resume state.** The previous standalone Zustand resume store has been retired; optimistic updates, refetching, and error recovery now flow through one cache, behaving consistently across tabs and reloads. * **Native page format and margins.** Page size and margin controls are now expressed directly to `@react-pdf/renderer`, replacing the Puppeteer-specific `printMarginTemplates` workaround. ## Self-Hosting * **One-service deployment.** Self-hosted Compose files no longer need a `printer:` service block. The minimum stack is now just Reactive Resume + PostgreSQL (with optional S3-compatible storage and SMTP). * **`/api/health` simplified.** The health endpoint now reports `database` and `storage` only, returning HTTP `503` if either dependency is unhealthy. There is no longer a `printer` field to monitor. * **Updated documentation.** The Self-Hosting, Quickstart, Development, Architecture, and Legal pages have all been refreshed to describe the simplified single-service deployment. ## Authentication & AI * **Better Auth retained end-to-end** with all nine plugins — passkeys, two-factor authentication, OAuth (Google / GitHub / LinkedIn / custom), API keys, dynamic OAuth client registration, dashboard, sentinel, and admin. Existing sessions and logins carry over after the upgrade. * **AI features carry over** (Resume Analysis, AI Chat with JSON Patch tool calls, PDF / DOCX import) with the same provider matrix (OpenAI, Google Gemini, Anthropic, Ollama, OpenRouter). The AI router and service layer have been cleanly decoupled from the jobs / tailor flow for a more modular surface. ## Removed * **Custom CSS option** in the resume builder. With rendering bound to `@react-pdf/renderer`, raw CSS no longer applies to the exported PDF. A structured customization API will return in a future release. * **`PRINTER_*` and `BROWSERLESS_*` environment variables**, the `printer/{resumeId}` route, the `getByIdForPrinter` server function, and the printer-token signing code are all gone. ## Maintenance * Removed dead printer-token utilities and the legacy public RPC surface for printer-only resume reads. * Tightened the boundary between server-only and client-only code: server modules (database, storage, auth) are lazy-imported so they no longer leak into the client bundle. * Reverse-proxy timeout guidance in the nginx example has been simplified now that no long-running PDF generation request flows through the proxy. **Full Changelog**: [v5.0.20...v5.1.0](https://github.com/amruthpillai/reactive-resume/compare/v5.0.20...v5.1.0) ## Features & Improvements * Added the new **Meowth** resume template (compact ATS-friendly layout with an inline three-column entry header), thanks to [@JamesGoslings](https://github.com/JamesGoslings). [#2923](https://github.com/amruthpillai/reactive-resume/pull/2923) * Added support for custom icon colors on section items, thanks to [@Ruzenie](https://github.com/Ruzenie). [#2928](https://github.com/amruthpillai/reactive-resume/pull/2928) * Improved account-related email UX with better templates for password reset and email verification. [b87f2007](https://github.com/amruthpillai/reactive-resume/commit/b87f2007) * Consolidated separate settings pages into a single **Integrations** page. [5d8126d4](https://github.com/amruthpillai/reactive-resume/commit/5d8126d4) ## Fixes * Added a targeted Chinese localization fix for the `Skills` section title (`zh-CN`). [#2931](https://github.com/amruthpillai/reactive-resume/pull/2931) * Allowed MCP localhost loopback only for local MCP clients, improving local integration behavior while keeping external access restrictions intact. [623ca5c6](https://github.com/amruthpillai/reactive-resume/commit/623ca5c6) ## Maintenance & Localization * Updated dependencies and lockfile, including cleanup of unused exports (Knip). [e1bccbcc](https://github.com/amruthpillai/reactive-resume/commit/e1bccbcc) * Synced translation catalogs from Crowdin. [#2922](https://github.com/amruthpillai/reactive-resume/pull/2922), [#2925](https://github.com/amruthpillai/reactive-resume/pull/2925), [#2926](https://github.com/amruthpillai/reactive-resume/pull/2926), [#2932](https://github.com/amruthpillai/reactive-resume/pull/2932), [#2934](https://github.com/amruthpillai/reactive-resume/pull/2934), [#2935](https://github.com/amruthpillai/reactive-resume/pull/2935) * Updated docs to list **Meowth** alongside existing templates. [#2929](https://github.com/amruthpillai/reactive-resume/pull/2929) **Full Changelog**: [v5.0.19...v5.0.20](https://github.com/amruthpillai/reactive-resume/compare/v5.0.19...v5.0.20) ## Highlights * Added **OpenRouter** as an AI provider, thanks to [@iagodemacedo](https://github.com/iagodemacedo). [#2906](https://github.com/amruthpillai/reactive-resume/pull/2906) * Added Chinese font options, thanks to [@Platinum1154](https://github.com/Platinum1154). [#2905](https://github.com/amruthpillai/reactive-resume/pull/2905) * Added text color support to the rich text editor, including DOCX export handling for colored text, thanks to [@Platinum1154](https://github.com/Platinum1154). [#2903](https://github.com/amruthpillai/reactive-resume/pull/2903) * Fixed MCP tool names for Claude Desktop compatibility. [#2885](https://github.com/amruthpillai/reactive-resume/pull/2885) * Improved Docker-based local development support and refreshed self-hosting setup guidance. [849aad64](https://github.com/amruthpillai/reactive-resume/commit/849aad64), [c0387298](https://github.com/amruthpillai/reactive-resume/commit/c0387298) ## Fixes & Security * Thank you to [@shaxbozaka](https://github.com/shaxbozaka) for running a security audit on Reactive Resume and helping make the app more secure. * Hardened auth, OAuth, AI URL validation, printer/export endpoints, resume access controls, Browserless configuration, and public route exposure. [a42dbcd4](https://github.com/amruthpillai/reactive-resume/commit/a42dbcd4) * Removed the public RPC surface for the printer-only resume fetch endpoint by moving it behind a server function, further shrinking the attack surface for `getByIdForPrinter`, thanks to [@shaxbozaka](https://github.com/shaxbozaka). * Corrected Computer Modern Sans italic font file mappings, thanks to [@russellbrenner](https://github.com/russellbrenner). [#2881](https://github.com/amruthpillai/reactive-resume/pull/2881) * Improved email handling and user lookup in OAuth configuration, thanks to [@VedantBhawsar](https://github.com/VedantBhawsar). [#2874](https://github.com/amruthpillai/reactive-resume/pull/2874) * Aligned role period text in experience items, thanks to [@JamesGoslings](https://github.com/JamesGoslings). [#2908](https://github.com/amruthpillai/reactive-resume/pull/2908) * Reduced resume preview wheel zoom sensitivity, thanks to [@GoldenSection0618](https://github.com/GoldenSection0618). [#2911](https://github.com/amruthpillai/reactive-resume/pull/2911) * Prevented orphaned section headings at page breaks, thanks to [@5queezer](https://github.com/5queezer). [#2851](https://github.com/amruthpillai/reactive-resume/pull/2851) * Added top margin handling for subsequent PDF pages, based on feedback from [@trigger-xyz](https://github.com/trigger-xyz). [bbc38d2f](https://github.com/amruthpillai/reactive-resume/commit/bbc38d2f) ## Maintenance & Localization * Updated dependencies and lockfile, including security-focused package pins and Vite+ version pins. [c6e8df0a](https://github.com/amruthpillai/reactive-resume/commit/c6e8df0a), [847d69b6](https://github.com/amruthpillai/reactive-resume/commit/847d69b6), [9b3916d4](https://github.com/amruthpillai/reactive-resume/commit/9b3916d4) * Added `SECURITY.md`. [9e1e593d](https://github.com/amruthpillai/reactive-resume/commit/9e1e593d) * Added focused tests for auth, printer/export, URL validation, form edge cases, rich text DOCX output, font handling, and CSS sanitization hardening. [d0af9f4b](https://github.com/amruthpillai/reactive-resume/commit/d0af9f4b) * Synced translation catalogs from Crowdin and moved syncing to GitHub Actions. [#2886](https://github.com/amruthpillai/reactive-resume/pull/2886), [#2918](https://github.com/amruthpillai/reactive-resume/pull/2918) ## New Contributors * [@russellbrenner](https://github.com/russellbrenner), [@VedantBhawsar](https://github.com/VedantBhawsar), [@JamesGoslings](https://github.com/JamesGoslings), [@GoldenSection0618](https://github.com/GoldenSection0618), [@iagodemacedo](https://github.com/iagodemacedo), and [@Platinum1154](https://github.com/Platinum1154) **Full Changelog**: [v5.0.17...v5.0.19](https://github.com/amruthpillai/reactive-resume/compare/v5.0.17...v5.0.19) ## Features & Improvements * Re-enabled **Passkeys** across authentication flows, including passkey sign-in on the login page and passkey management in account settings. ## Maintenance * Updated dependencies and lockfile. * Synced translation catalogs from Crowdin. ## Features & Improvements * Added **Resume Analysis** in the resume builder right sidebar: run an on-demand AI review for an overall score (0 to 100), a dimension scorecard, strengths, and prioritized suggestions. Results are saved per resume and reload after refresh. * When AI features are disabled, the analysis section shows a short notice with a link to **AI Settings** so you can enable your provider and model first. * Improved the **MCP server** experience: updated tools, resources, and prompts; added an MCP server card at `/.well-known/mcp/server-card.json` for compatible clients; refreshed the **Using the MCP server** guide. ## Fixes * Fixed [#2865](https://github.com/amruthpillai/reactive-resume/issues/2865), incorrect spacing between resume section items in shared layouts. * Fixed [#2868](https://github.com/amruthpillai/reactive-resume/issues/2868) affecting resume item presentation and linked titles in shared item components. ## Maintenance & CI * Downgraded the Cosign installer action to v3 in the Docker build workflow for more reliable image signing. * Synced translation catalogs from Crowdin. [#2864](https://github.com/amruthpillai/reactive-resume/pull/2864) * Dependency and lockfile updates (including changes bundled with MCP and analysis work). ## Features & Improvements * Updated shared resume item layouts (Experience, Education, Awards, Certifications, Publications, References, Volunteer) for better alignment and spacing consistency. * Generated printer pages now set a meaningful document title from the resume owner's name (` - Resume`) for cleaner PDF metadata and tab titles. [#2863](https://github.com/amruthpillai/reactive-resume/pull/2863) ## Fixes * Fixed [#2733](https://github.com/amruthpillai/reactive-resume/issues/2733), where date ranges could appear on a separate line unexpectedly in resume items. [#2862](https://github.com/amruthpillai/reactive-resume/pull/2862) * Adjusted Experience section form field ordering/labels so `Location`, `Position`, and `Period` are mapped and displayed correctly. ## Maintenance & Localization * Synced translation catalogs across all supported locales. * Updated dependencies and lockfile, including AI SDK, TipTap, TanStack Query, and Vite+ package aliases. ## Features & Improvements * Added **LinkedIn sign-in** support for self-hosted instances, including sign-in on the auth page and account linking in settings. * Improved the sign-in experience by showing loading placeholders while social login providers are being fetched. * Resume builder panel sizes are now persisted more reliably, making the layout feel more consistent between sessions. * Added clearer labels for resume sorting and filtering controls on the dashboard. ## Fixes * Improved autosave reliability in the resume builder: * Unsaved edits are flushed before page unload. * You now get a clear persistent warning if changes fail to save (for example, due to network issues). * Strengthened authentication defaults by increasing the minimum password length requirement to 8 characters. * Improved reliability around resume deletion and server-side error handling for create/update operations. * Fixed a rare language mix-up during printing/export when multiple print jobs run at the same time, so each PDF/screenshot now reliably uses the correct locale. * Improved print stability under heavy usage by reusing in-progress PDF and screenshot generation requests for the same resume instead of starting duplicate jobs. * Hardened printer token signing and token/session/API-key verification paths for better security. * Improved resilience in AI tailoring output parsing and JSON Resume import normalization. * Printer service now provides descriptive error messages ("Failed to generate PDF" / "Failed to capture screenshot") instead of generic internal server errors. * Job descriptions in the job detail sheet now render HTML formatting (headings, lists, bold text) instead of showing raw tags. * Fixed the "Tailor Resume" button being incorrectly disabled when AI is not configured — the dialog already supports plain resume duplication as a fallback. * Fixed the tailor resume flow to open the resume builder in a new tab while keeping the job listing open for reference, instead of navigating away and auto-opening the application page. * Apply option links in the job detail sheet are now validated before rendering, preventing malformed or potentially unsafe URLs. * Improved job card loading skeletons to match the actual card layout (logo, title, badges). * Centered the "Configure Job Search" empty state on the page. * Extracted the `JobCard` component into its own file for better code organization. ## Docs & Localization * Updated self-hosting and environment variable documentation to include LinkedIn OAuth configuration. * Synced translations across locales for the latest authentication and save-status messaging. ## Features * Implemented OAuth 2.1 support for MCP authentication, thanks to @5queezer. [#2829](https://github.com/amruthpillai/reactive-resume/pull/2829) * Migrated from using Biome to Oxlint/Oxfmt for linting and formatting, with a new autofix CI workflow. [#2822](https://github.com/amruthpillai/reactive-resume/pull/2822) ## Fixes * Fixed an issue with the slider component for "Sidebar Width" in the resume builder. [#2830](https://github.com/amruthpillai/reactive-resume/issues/2830) ## Features & Improvements * Added **Job Listings with AI-Powered Resume Tailoring**, a major new feature that integrates job search (via JSearch API) directly into the dashboard with AI-driven resume tailoring to match job descriptions. [#2788](https://github.com/amruthpillai/reactive-resume/pull/2788) * Search for jobs with filters for location (city, state, country), employment type, remote status, and more. * View detailed job listings in a slide-out panel with apply links and tags. * Tailor your resume to a specific job posting using AI — rewrites skills, experience, and references for optimal fit. * Per-user API quota management with usage tracking in settings. * Pagination with 30 results per page. * Added **DOCX resume export** — generate and download tailored resumes as Word documents. [#2788](https://github.com/amruthpillai/reactive-resume/pull/2788) * Migrated the entire project toolchain to **Vite+** (`vp` CLI), unifying Vite, Vitest, Oxlint, and Oxfmt under a single developer experience. * Migrated from **Biome to Oxlint/Oxfmt** for linting and formatting, with a new autofix CI workflow. [#2822](https://github.com/amruthpillai/reactive-resume/pull/2822) * Added **Slovenian** locale support. * Added a new `Progress` UI component. ## Fixes * Fixed type issues in auth client and configuration. * Used RTL-friendly CSS classes across the app for improved bidirectional layout support. * Removed dead code and unused imports. * Updated route tree generation and added `routeTree.gen.ts` to `.gitignore`. * Improved animation performance with `willChange` styles on animation components. ## Maintenance & Dependencies * Updated dependencies across the board, including `@typescript/native-preview`, `vite-plus`, and others. * Added database migrations for missing indexes. * Synced translations from Crowdin. [#2820](https://github.com/amruthpillai/reactive-resume/pull/2820), [#2824](https://github.com/amruthpillai/reactive-resume/pull/2824) * Updated French translation for 'Volunteer' to 'Bénévolat'. [#2823](https://github.com/amruthpillai/reactive-resume/pull/2823) * Multiple translation and language updates across all locales. ## New Contributors * @lukadfagundes * @Hephaisto-dev ## Features & Improvements * Refactored the component system to `@base-ui/react` across the app for standardized UI behavior (dialogs, menus, accordions, comboboxes, switches, etc.). * Improved auth infrastructure with Better Auth dashboard/sentinel integration and expanded IP/header handling for proxied deployments. * Added a dedicated `src/server.ts` server entry using `FastResponse` for better runtime compatibility. * Sidebar button list now scrolls internally on overflow. ## Fixes * Printer endpoint now resolves to IP when using chromedp, improving compatibility with proxied deployments. * Switched OpenAI integration to `chat/completions` for resume import and AI features. * AI PDF/DOCX resume parsing is now more reliable via direct file send (multimodal input). * Resume import normalization hardened: section defaults merged, required fields enforced, missing IDs/flags autogenerated. * Fixed UI migration regressions (accordion behavior, button interaction, right sidebar scrollbar). * Fixed multi-page PDF crashes and Gemini API ingestion errors. * Fixed role title styling, role spacing, and issues with skills item rendering and template headings. ## Maintenance & Dependencies * Updated dependencies and lockfile. * Synced translation strings across locales, including multiple contributions from Crowdin. * General dependency and code style improvements, plus removal of redundant indexes and plugins. ## New Contributors * @yang-summer * @FrancocDev * @obitton * @jondycz ## Fixes * Show section titles for summary-type custom sections in the resume builder. [#2744](https://github.com/amruthpillai/reactive-resume/pull/2744) * Prevent browser password managers and Edge autofill/save prompts from appearing on AI settings API key fields. [#2719](https://github.com/amruthpillai/reactive-resume/pull/2719) * Replace deprecated Tailwind CSS classes: use `inset-s-*`/`inset-e-*` instead of `start-*`/`end-*`. * Fix PDF downloader to work correctly in offline mode. [#2743](https://github.com/amruthpillai/reactive-resume/pull/2743) * Make bold formatting visible for `` in the resume rich text editor (uses plain `font-weight: bold` fallback if the CSS variable is unset). Fixes [#2730](https://github.com/amruthpillai/reactive-resume/issues/2730) * Prevent credentials sign-in from dropping `session_token` Set-Cookie, improves login reliability. [#2718](https://github.com/amruthpillai/reactive-resume/pull/2718) * Remove redundant `resume-` prefix from download filename; add spacing between pages in shared view. [#2709](https://github.com/amruthpillai/reactive-resume/pull/2709) * Normalize autocomplete tokens for login and register forms. [#2714](https://github.com/amruthpillai/reactive-resume/pull/2714) * Fix improper chips reordering and update dependency/translations. [#2711](https://github.com/amruthpillai/reactive-resume/issues/2711) * Fix clipping of heading in Lapras resume template. * Remove error-causing plugins in oRPC integration. * Remove duplicate database indexes; add index for `created_at` on user and resume tables. ## Features & Improvements * Added feature flag: `FLAG_DISABLE_IMAGE_PROCESSING` (allows disabling image processing site-wide). * Updated Discord invite link in the app and documentation. * Added codebase and architecture documentation in `CLAUDE.md`. * Synced latest translations from Crowdin (multiple language updates and additions). ## Maintenance & Other * Refactored auth utility from `originWith` to `withHostname` to preserve localhost/127.0.0.1 sibling trust. * Updated dependencies and improved code style. * Updated documentation and README files. ## Features & Improvements * Added Computer Modern web fonts to the font selector, allowing users to choose from LaTeX-style "Computer Modern" fonts for a classic scientific look. * Updated dependencies to the latest versions. ## Fixes * Removed Passkey support from the authentication system due to provider compatibility issues. * Updated dependencies to the latest versions. ## Features & Improvements * Introduced a new **MCP (Model Context Protocol) server** for managing and editing resumes from MCP-compatible AI tools (Claude Desktop, Cursor, Codex, and others). Supports listing, reading, creating, deleting, locking/unlocking, and patching resumes via natural language. [(guide)](/guides/using-the-mcp-server) * Added an **AI Chat** panel to the resume builder, allowing conversational resume modifications through tool-calling (JSON Patch operations applied to the resume in real time with visual feedback). * Added a system prompt and `patch_resume` tool for structured, minimal-diff resume edits via RFC 6902 JSON Patch. * Chat history is now persisted per resume in localStorage. ## Fixes * Fixed rendering issues in the Lapras and Onyx resume templates. * Improved Combobox and ScrollArea UI components. * Fixed skills item rendering in shared resume components. * Updated authentication configuration and route handling. * Updated JSON Schema to match the latest resume data model. ## Maintenance * Updated dependencies to latest versions. ## Features & Improvements * Implemented Atomic Resume Patching API for fine-grained, partial updates to resumes via a new PATCH endpoint. [#2692](https://github.com/amruthpillai/reactive-resume/pull/2692) * API endpoint `PUT /resume/{id}` now returns the updated resume object rather than void, with explicit DTOs for input/output. [#2688](https://github.com/amruthpillai/reactive-resume/pull/2688) * Added error logging for API server errors (server-side only) to improve debugging and reliability. * Refactored and cleaned up imports/exports for clarity and maintainability. * Added `.devcontainer` configuration for improved contributor development environment. * Added build status badge and documentation link to README. ## Fixes * General bug fixes and minor improvements. * Synced latest translations from Crowdin (notably: French, other languages). * Updated dependencies to latest versions. ## Features & Improvements * Implemented Cover Letter functionality as a custom section in the resume builder. [(link)](/guides/adding-a-cover-letter) * Added full-screen mode to the rich text editor for distraction-free writing. * Introduced a new custom section type: `summary`, enabling users to add extra summary sections. * Added `useFormBlocker` hook to prevent dialogs from being closed with unsaved form changes. ## Fixes * Fixed keyword spacing issue in the interests section. [#2631](https://github.com/amruthpillai/reactive-resume/pull/2631) * Fixed AI connection test and improved error reporting for AI provider issues. ## Features & Improvements * Brought back Undo/Redo functionality in the resume builder for an improved editing experience. * Sidebar builder now arranges dynamically based on the section type in each template. [#2564](https://github.com/amruthpillai/reactive-resume/pull/2603) * Added PWA (Progressive Web App) support and updated PDF example file links in documentation. ## Fixes * Removed extra spacing when proficiency is empty. [#2607](https://github.com/amruthpillai/reactive-resume/pull/2626) * Fixed Pikachu template: header/page picture rendering, and respect for `fullWidth` property. * General template improvements for layout and rendering consistency. * Fixed GitHub OAuth login for users migrated from previous versions. * Improved printer service communication and reduced resource usage for more reliable PDF generation. * Fixed "empty" Git merge remnants in codebase. ## Maintenance * Synced translations from Crowdin (Afrikaans, Persian, Portuguese/Brazilian, others). * Updated translation sources and configuration. * Updated package dependencies and fixed self-hosting guide links in README. * Removed dead code and updated screenshots. * Other bug fixes and minor improvements (#2542, #2573, #2598). ## Features & Improvements * Added support for printing Free-Form PDFs (no fixed page height), allowing for custom-fit page content. [(link)](/guides/selecting-page-format) * Allow overriding the default endpoint for all AI providers, not just Ollama; default endpoint now visible in AI settings. * Updated the chip input component: supports adding, editing, removing, and reordering keywords for skills and other sections. * Improved RTL support across the app, thanks to @obreo. [(link)](https://github.com/amruthpillai/reactive-resume/pull/2583) ## Fixes * Updated translation configuration to remove line numbers, reducing unnecessary diffs. * Homepage video optimized for faster loading without quality loss. * Increased screenshot TTL for resumes to reduce unnecessary regenerations. * Updated dependencies and translations to latest versions. ## Features & Improvements * Added an agent skill `skills/resume-builder` for agentic AI assistants, enabling resume construction through conversational AI. * Added a guide for how to fit content on a page when exporting to PDF. [(link)](/guides/fitting-content-on-a-page) * Alert user when content is too tall for a page for easier export troubleshooting. ## Fixes * Ditgar template now respects `fullWidth` setting. * Updated JSON Schema for proper format. * Updated Discord server invite link. * Updated dependencies to latest versions. ## Maintenance & Fixes * Updated translations from Crowdin. * Added Community Spotlight section to the documentation. * Removed `-r require-metadata` from the Dockerfile (was not needed). * Fixed inconsistencies in Docker compose documentation examples. * Fixed username validation to allow hyphens. * Fixed issues with the printer service's screenshot and PDF endpoints. This release is a major overhaul of Reactive Resume. The app was redesigned and rebuilt from scratch. **Highlights:** * 2 new resume templates: *Ditgar* and *Lapras* * Passkeys for authentication * Entirely new user interface and refreshed design * API access and reference docs * AI Integration with OpenAI, Google, Anthropic, and Ollama * Improved font selector with real-time preview * Expanded and improved documentation, with more how-to guides * Redesigned template gallery with detailed views * Resume import from PDF/DOCX (requires AI Integration) * Stronger infrastructure for better reliability and scalability * Drag-and-drop for moving items between sections and pages * New CSS Editor with autocompletion and highlighting * Custom sections now support typed extension for finer control * Icon style selector for indicators (stars, circles, custom, etc.) * Sidebar width adjustment and full-width page support That list is not exhaustive. Send feedback via [contact](https://amruthpillai.com/#contact) or [GitHub issues](https://github.com/amruthpillai/reactive-resume/issues). # Sponsors Source: https://docs.rxresu.me/community/sponsors The sponsors whose support funds ongoing development and hosting of Reactive Resume. Sponsors pay for hosting, maintenance, and ongoing development, which is what keeps Reactive Resume free and independent. Thank you to everyone who chips in. ## Atlas Cloud Atlas Cloud [Atlas Cloud](https://www.atlascloud.ai/?utm_source=github\&utm_medium=link\&utm_campaign=reactive-resume) supports Reactive Resume as a project sponsor. Atlas Cloud provides a unified AI platform for developers, with access to hundreds of models for chat, image generation, video generation, media processing, and GPU cloud workloads through one API key, one endpoint, and one billing account. Learn more at [atlascloud.ai](https://www.atlascloud.ai/?utm_source=github\&utm_medium=link\&utm_campaign=reactive-resume). ## Sponsor Reactive Resume If your company would like to sponsor Reactive Resume, email [hello@amruthpillai.com](mailto:hello@amruthpillai.com). # Spotlight Source: https://docs.rxresu.me/community/spotlight Articles, videos, tutorials, and social media posts about Reactive Resume, shared by the community. Have you built something with Reactive Resume, or spread the word about it in your own way? I'd love to feature it here. Email me at [hello@amruthpillai.com](mailto:hello@amruthpillai.com) and I'll add it to this page. *** ## Articles A collection of blog posts and articles written by the community about Reactive Resume. No articles have been featured yet. *** ## Videos Video tutorials, reviews, and walkthroughs created by the community. No videos have been featured yet. *** ## Social media Posts and threads from social media platforms sharing experiences with Reactive Resume. No social media posts have been featured yet. # Reactive Resume vs Adobe Express Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-adobe-express Compare Reactive Resume and Adobe Express for resume templates, PDF export, visual editing, structured data, and self-hosting. Adobe Express suits you when the resume sits inside broader document, image, and layout work. Reactive Resume keeps the content in resume-specific fields, with resume-focused exports and a choice of where the app runs. Adobe Express has a resume maker inside a general creative editor. Reactive Resume only does resumes: it organizes sections such as experience and education, renders them in a template, and keeps the same data when you change layouts or create new versions. ## Quick comparison | Consideration | Reactive Resume | Adobe Express | | ---------------- | -------------------------------------------------------- | ------------------------------------------------------- | | Primary workflow | Resume-specific fields and templates | General visual editing with resume templates | | Editing scope | Resume layout, typography, colors, spacing, and sections | Document, image, layout, and graphic editing | | Exports | PDF, DOCX, Markdown, and Reactive Resume JSON | Resume creation and export options in Adobe Express | | Content reuse | Structured data can be reused across resume versions | Reuse designs and assets in the Adobe Express workflow | | Deployment | Hosted use or self-hosting under an MIT license | Adobe-hosted service | | Free plan | Core hosted resume workflow has no premium tier | Free-plan features and asset access have defined limits | Adobe Express says its resume maker includes customizable resume templates. Its wider editor suits people who need to combine a resume with edited images or custom page layouts. Check its [Free plan documentation](https://helpx.adobe.com/express/web/adobe-express-subscription/free.html) for current feature and asset boundaries before you rely on a particular tool. ## Where Adobe Express is a better fit Use Adobe Express when the resume is one part of a wider visual document. Its editing tools help with placing images, adjusting graphics, or building layouts that no resume template covers. It is also a practical choice when you already use Adobe Express for related documents or visual content. The wider editor is the real advantage. It handles work that falls outside a resume builder's controls. Confirm plan and content availability for the assets or features you need instead of assuming a free account includes them all. ## Where Reactive Resume is a better fit Use Reactive Resume when work history and other sections should stay structured rather than sit on the page as arranged elements. That makes it easier to prepare targeted versions, switch templates, or keep a data backup next to your document exports. The [exporting guide](/guides/exporting-your-resume) covers PDF, DOCX, Markdown, and JSON. There are also options beyond the hosted app. The project is [open source](/use-cases/open-source-resume-builder) under MIT and supports [self-hosting](/use-cases/self-hosted-resume-builder). Those only matter if you need them; for a single visual document, Adobe Express is the more direct editor. ## Which should you choose? Choose Adobe Express when broad creative editing, visual assets, or a general document canvas are central to the task. Choose Reactive Resume when the resume itself is the task and you want reusable structured fields, resume-specific controls, and several export formats. Both services produce a PDF for sharing. The decision comes down to the editing model: a general creative workspace or a focused resume editor. ## Reactive Resume limitations in this comparison Reactive Resume has a smaller visual asset library and no general-purpose design canvas. It is the wrong tool for heavy image work, graphic composition, or producing many non-resume document types. Adobe Express fits those needs better. ## Sources * [Adobe Express resume maker](https://www.adobe.com/express/create/resume) * [Adobe Express Free plan](https://helpx.adobe.com/express/web/adobe-express-subscription/free.html) Last checked: July 28, 2026 Try Reactive Resume when reusable work history and resume-specific controls matter more than general document design. # Reactive Resume vs Canva Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-canva Compare Reactive Resume and Canva for free resume creation, visual control, exports, data portability, and self-hosting. Canva suits freeform visual composition and gives you a broad design library. Reactive Resume is built around structured resume fields, reusable resume data, and the option to self-host. Both tools make resumes, but they start from different models. Canva is a general design product with resume templates among its design types. Reactive Resume is a resume editor: work history, education, skills, and other sections are stored as data, then rendered through the template you pick. ## Quick comparison | Consideration | Reactive Resume | Canva | | ---------------- | --------------------------------------------------------- | --------------------------------------------------------------- | | Primary workflow | Structured resume sections with a live preview | Freeform visual editing across many design types | | Design controls | Resume templates, colors, typography, layout, and spacing | Flexible composition, elements, and a broad design library | | Exports | PDF, DOCX, Markdown, and Reactive Resume JSON | See Canva's export options and template terms | | Data portability | JSON export can back up or restore a resume | Depends on the design and export format you choose | | Deployment | Hosted use or self-hosting under the MIT license | Canva-hosted service | | Plan boundary | The hosted core resume workflow has no premium tier | Some Canva content and features have plan-specific availability | Reactive Resume supports [PDF, DOCX, Markdown, and JSON exports](/guides/exporting-your-resume). Its JSON format holds the content and settings so you can reuse them in another Reactive Resume resume. Canva's resume builder is part of a wider design environment, which fits better when the resume needs custom graphics, brand elements, or a layout beyond resume-specific controls. ## Where Canva is a better fit Choose Canva when visual composition is the main task. Its resume page points to a large collection of customizable templates, and the wider product arranges text, images, and graphic elements. That helps when a resume has to match an existing portfolio, brand kit, or presentation style. Canva is also the convenient option when you are preparing related design material at the same time, such as a portfolio cover, a social graphic, or a presentation. Check availability and licensing for the individual templates, elements, and features you pick. A free Canva account does not mean every asset is included. ## Where Reactive Resume is a better fit Choose Reactive Resume when the content should stay in recognizable resume fields and you expect to reuse it across versions. You can change a template without re-entering the underlying sections, adjust resume layout settings, and export in several document and data formats. It also fits when you care about infrastructure. Reactive Resume is [MIT-licensed](/legal/license), its source is public, and you can deploy it yourself. The [self-hosting guide](/self-hosting/docker) covers the Docker path, and hosted use stays available if you would rather not run the service. ## Which should you choose? Use Canva if the resume is mainly a visual design project and you want a general canvas with a broad asset library. Use Reactive Resume if you want a dedicated resume workflow, portable resume data, and the option to run the software yourself. For a typical application, either workflow ends in a PDF. The difference is whether you compose each page as a design or manage resume sections and template settings separately. ## Reactive Resume limitations in this comparison Reactive Resume has a narrower design canvas. It does not try to match Canva's general composition tools or its asset library. If your resume depends on custom illustrations, heavy image editing, or unusual page composition, Canva gives you more direct control. ## Sources * [Canva resume builder](https://www.canva.com/create/resumes/) Last checked: July 28, 2026 Use structured resume sections and keep the option to export or self-host when you do not need a general design canvas. # Reactive Resume vs CareerCircle Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-careercircle Compare Reactive Resume and CareerCircle by free PDF and Word exports, career resources, accounts, open source, and self-hosting. CareerCircle puts resume drafting next to job listings, courses, and professional-development resources. Reactive Resume is a standalone resume tool built around resume ownership, export formats, and self-hosting. ## Quick comparison | Consideration | Reactive Resume | CareerCircle | | --------------- | ----------------------------------------------- | ----------------------------------------------------- | | Resume workflow | Structured resume editor with reusable versions | Resume builder within a career-services platform | | Downloads | PDF, DOCX, Markdown, and JSON | PDF and Microsoft Word downloads | | Writing support | Direct editing and optional AI | Guidance and tips from staffing experts | | Career services | Resume and application tools | Jobs, courses, and professional-development resources | | Account | An account stores resume versions | Sign-up is required to use the service | CareerCircle documents PDF and Microsoft Word downloads from its resume builder. It puts staffing-expert guidance, job search, courses, and professional-development resources in the same service. Reactive Resume supports [PDF, DOCX, Markdown, and JSON exports](/guides/exporting-your-resume), and its [dashboard](/guides/managing-resumes-from-the-dashboard) keeps separate resume versions. Its source is public under the [MIT license](/legal/license), with a Docker self-hosting path. ## Where CareerCircle is a better fit Choose CareerCircle when you want the resume builder connected to job search, courses, and professional-development resources. Its staffing-expert guidance also helps if you prefer to get that advice inside the same career service. ## Where Reactive Resume is a better fit Pick Reactive Resume to keep several resume versions and export them in document or data formats. You can also run the software yourself; see the [self-hosting guide](/self-hosting/docker). ## Which should you choose? Choose CareerCircle for a sign-up-based career service with its resume builder, jobs, courses, and professional-development resources. Choose Reactive Resume for a standalone resume system with reusable data and self-hosting. ## Reactive Resume limitations in this comparison Reactive Resume has none of CareerCircle's course, job, and community services. If those resources should sit alongside the resume workflow, CareerCircle is the closer fit. ## Sources * [CareerCircle resume builder](https://www.careercircle.com/resume-builder) Last checked: July 28, 2026 Try Reactive Resume when resume ownership, multiple export formats, and self-hosting matter more than bundled career services. # Reactive Resume vs Freesumes Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-freesumes Compare Reactive Resume and Freesumes by no-account use, PDF export, templates, saved resume management, privacy, and self-hosting. Freesumes is built for making one resume in a browser session, without an account or a card. Reactive Resume saves your resumes instead, and adds several export formats, sharing, and automation. ## Quick comparison | Consideration | Reactive Resume | Freesumes | | ---------------------- | ------------------------------------------------- | --------------------------------------------------------- | | Account | Account-backed resume management | No account or credit card for the builder | | Builder templates | Select a template for each saved resume | Six current builder templates | | PDF | PDF export | PDF download | | Other template formats | DOCX, Markdown, and JSON exports | Separate Word and Google Docs templates | | Data handling | Resumes persist in the account and server storage | Builder data is wiped when the tab is refreshed or closed | Freesumes documents a no-account, no-card builder with six templates and PDF output. It offers Word and Google Docs templates separately. Its builder says it does not collect or store what you enter, and that the data is wiped when you refresh or close the browser tab. Reactive Resume keeps resume versions in its [dashboard](/guides/managing-resumes-from-the-dashboard), with [PDF, DOCX, Markdown, and JSON exports](/guides/exporting-your-resume). It can also [share resumes](/use-cases/export-and-share-resumes) and run API or MCP automation. ## Where Freesumes is a better fit Choose Freesumes for a one-off browser session without an account or card, if you accept that the builder data disappears on refresh or close. Its separate Word and Google Docs templates also suit an editor-first workflow. ## Where Reactive Resume is a better fit Reactive Resume holds on to your resume versions so you can share them or export them in several formats. It can also be self-hosted; see the [Docker guide](/self-hosting/docker). ## Which should you choose? Choose Freesumes for a no-account, browser-session PDF workflow or its separate Word and Google Docs templates. Choose Reactive Resume when you want saved resume management, sharing, several export formats, or automation. ## Reactive Resume limitations in this comparison Reactive Resume needs an account and stores resumes on the server. That is a drawback if you want a one-off local browser session where the builder data disappears on refresh or close. ## Sources * [Freesumes resume builder](https://www.freesumes.com/resume-builder/) * [Freesumes builder privacy behavior](https://www.freesumes.com/build-resume) * [Freesumes Word and Google Docs templates](https://www.freesumes.com/free-resume-templates-for-ms-word/) Last checked: July 28, 2026 Use Reactive Resume when you want persistent resume versions, multiple export formats, sharing, and automation. # Reactive Resume vs Jobscan Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-jobscan Compare Reactive Resume and Jobscan by free PDF creation, ATS parse checking, job matching, exports, open source, and automation. Jobscan makes sense when your workflow revolves around its hosted resume scanner and the match rate it reports against a job description. Reactive Resume gives you structured resume data, several export formats, open-source deployment, and API or MCP automation, plus a free ATS checker that measures how well your file parses rather than predicting an outcome. ## Quick comparison | Consideration | Reactive Resume | Jobscan | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | Resume creation | Structured editor with PDF, DOCX, Markdown, and JSON exports | Free builder with nine current templates and PDF download | | Import | Supported resume imports | Existing-resume and LinkedIn import | | Analysis | Built-in ATS checker, free: a parse-quality score, a pass/warn/fail checklist, and optional job-description keyword coverage, all computed in your browser | Separate resume scanner producing a match rate against a job description | | Automation | Authenticated API and MCP workflows | Separate scanner workflow | Jobscan's builder documents a free PDF-creation workflow, LinkedIn import, and nine ATS-friendly templates. Its separate scanner lists resume scoring, formatting checks, and job-listing analysis as product features. Those are vendor claims about the product, not guarantees about ATS handling or hiring outcomes. Reactive Resume exports PDF, DOCX, Markdown, and JSON, and it supports authenticated automation through its API and MCP server. Its [ATS checker](/guides/using-the-ats-checker) scores how faithfully software can extract your PDF and lists which of a posting's terms already appear in it. It reports no match rate and predicts no rejection, because neither is knowable from the file. ## Where Jobscan is a better fit Choose Jobscan when a match rate against a specific posting, and the recommendations that come with it, drive your review process. Its scanner is a paid, hosted product built around that number. ## Where Reactive Resume is a better fit Reactive Resume is the better choice when you want to own structured resume data, pick a template, export in several formats, or automate authenticated resume workflows. Its API and MCP server support scripts, integrations, and compatible AI clients. ## Which should you choose? Choose Jobscan when a match rate against each posting is your primary need. Choose Reactive Resume when the builder, data portability, self-hosting, and automation come first, and a free local parse-quality check covers the rest. ## Reactive Resume limitations in this comparison Reactive Resume's ATS checker measures file properties: whether the text extracts, in what order, and whether your facts survive. It produces no match rate against a posting and makes no claim about predicting a rejection. If you want a documented match-rate score, Jobscan is the more direct fit. ## Sources * [Jobscan resume builder](https://www.jobscan.co/resume-builder) * [Jobscan resume scanner](https://www.jobscan.co/resume-scanner) * [Reactive Resume: using the ATS checker](/guides/using-the-ats-checker) * [Reactive Resume: exporting your resume](/guides/exporting-your-resume) * [Reactive Resume: using the API](/guides/using-the-api) * [Reactive Resume: using the MCP server](/guides/using-the-mcp-server) Last checked: July 28, 2026 Upload a PDF and see what an applicant tracking system can read from it. Runs in your browser; no account needed. # Reactive Resume vs Kickresume Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-kickresume Compare Reactive Resume and Kickresume by free downloads, AI writing, content examples, templates, provider choice, and self-hosting. Kickresume bundles AI writing, imports, examples, and related career documents into one guided product. Reactive Resume is an open-source editor whose core hosted workflow has no premium tier, with optional provider-configured AI and self-hosting. ## Quick comparison | Consideration | Reactive Resume | Kickresume | | ------------- | ----------------------------------------------------- | ----------------------------------------------------------------------- | | AI | Optional; connect and configure your own provider | Integrated AI writing and rewriting tools | | Content help | Direct editing and AI assistance after provider setup | Examples, guides, and AI-generated drafts | | Imports | Supported resume imports | LinkedIn and PDF/DOCX import paths | | Documents | Resume-focused exports and versions | Resumes, cover letters, websites, and related tools | | Free plan | Core hosted workflow has no premium tier | Unlimited documents and downloads when using free customization options | Kickresume's help center documents AI writing, LinkedIn import, PDF import, examples, guides, and cover-letter and website workflows. Its free-plan FAQ says documents and downloads are unlimited when you use free customization options; premium-marked options fall outside that. Reactive Resume exports PDF, DOCX, Markdown, and JSON. Its AI stays optional: you connect a provider, a model, an endpoint when one is needed, and an API key. The provider may charge you separately. ## Where Kickresume is a better fit Choose Kickresume when you want prewritten examples, guided prompts, built-in AI writing, or related career documents in one interface. Its import options also help when you are starting from a LinkedIn profile or an existing PDF or DOCX resume. ## Where Reactive Resume is a better fit Reactive Resume is the better choice when you want AI to stay optional and want to pick the provider that handles your resume content. It is open source, can be self-hosted, and has API and MCP workflows for authenticated automation. ## Which should you choose? Choose Kickresume for a bundled writing, examples, and career-document workflow. Choose Reactive Resume for structured resume data, several export formats, deployment control, or configurable AI and automation. ## Reactive Resume limitations in this comparison Reactive Resume has a smaller built-in library of content examples and needs provider setup before its AI features work. It does not bundle Kickresume's wider guided career-document workflow. ## Sources * [Kickresume general help and plan FAQ](https://www.kickresume.com/en/help-center/general/) * [Kickresume resume editor help](https://www.kickresume.com/en/help-center/resume/) * [Reactive Resume: AI resume builder](/use-cases/ai-resume-builder) * [Reactive Resume: using AI](/guides/using-ai) * [Reactive Resume: API and MCP automation](/use-cases/api-mcp-resume-automation) Last checked: July 28, 2026 Try Reactive Resume when you want AI to remain optional and configurable rather than bundled into the builder. # Reactive Resume vs LiveCareer Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-livecareer Compare Reactive Resume and LiveCareer by free downloads, guided content, resume checks, templates, open source, and self-hosting. LiveCareer gives you ready-made content, spell-checking, writing tips, and ResumeCheck while you draft. Reactive Resume has no built-in checker; it gives you PDF or DOCX export and access to the source. ## Quick comparison | Consideration | Reactive Resume | LiveCareer | | ---------------- | ------------------------------ | ---------------------------------------------------- | | Free download | PDF, DOCX, Markdown, and JSON | TXT | | PDF and Word | Included export formats | Require premium access for unlimited downloads | | Drafting support | Direct editing and optional AI | Ready-made content, spell-checking, and writing tips | | Resume review | No native checker product | ResumeCheck identifies common issues | LiveCareer documents TXT as the free builder's download format, and unlimited PDF and Word downloads under premium access. The product also documents ready-made content, spell-checking, writing tips, and ResumeCheck. Reactive Resume supports [PDF, DOCX, Markdown, and JSON exports](/guides/exporting-your-resume). Its [AI workflow](/guides/using-ai) is optional and provider-configured, and its source is public under the [MIT license](/legal/license). ## Where LiveCareer is a better fit Choose LiveCareer when ready-made content, spelling checks, writing tips, and a resume checker matter while you draft. Those tools help if you want the review features in the same product as the builder. ## Where Reactive Resume is a better fit Use Reactive Resume when PDF or DOCX output, reusable resume data, or source access come first. You can also self-host it; the [Docker guide](/self-hosting/docker) covers that path. ## Which should you choose? Choose LiveCareer when its guided content and checker suit how you draft and TXT output is enough without premium access. Choose Reactive Resume when you want PDF or DOCX output and a self-hosting option. ## Reactive Resume limitations in this comparison Reactive Resume has a smaller guided-content and checker surface. It has no equivalent to LiveCareer's ready-made content, spell-checking, writing tips, or its ResumeCheck product. ## Sources * [LiveCareer pricing](https://www.livecareer.com/pricing) * [LiveCareer resume builder](https://www.livecareer.com/t3) Last checked: July 28, 2026 Try Reactive Resume when PDF or DOCX output matters more than ready-made writing suggestions. # Reactive Resume vs MyPerfectResume Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-myperfectresume Compare Reactive Resume and MyPerfectResume by free downloads, writing guidance, templates, AI, open source, and self-hosting. MyPerfectResume is built around guided writing: step-by-step prompts, expert-written content suggestions, and a resume checker. Reactive Resume is an open-source editor whose core hosted workflow has no premium tier and includes PDF, DOCX, Markdown, and JSON exports, but it has no equivalent content library or specialized checker. ## Quick comparison | Consideration | Reactive Resume | MyPerfectResume | | --------------------- | ----------------------------------------------- | --------------------------------------------------- | | Free final download | PDF, DOCX, Markdown, and JSON | Plain-text TXT | | Designed PDF and Word | Included exports | Require premium access | | Writing help | Direct editing; optional provider-configured AI | Step-by-step prompts, tips, and content suggestions | | Checking tools | No equivalent specialized checker | ResumeCheck feedback is listed with premium access | | Deployment | Hosted use or self-hosting | Hosted service | MyPerfectResume's free-builder guide says free accounts get tailored content suggestions, expert tips, and unlimited plain-text downloads, and that PDF or Word template downloads need a premium plan. Its pricing page lists TXT downloads with basic access and puts PDF, Word, and ResumeCheck behind premium access. Reactive Resume takes a different path: you get a rendered [PDF, DOCX, Markdown, or JSON export](/guides/exporting-your-resume) with no premium tier. That helps most when you already know what to write and want both a presentation-ready document and reusable resume data. ## Where MyPerfectResume is a better fit MyPerfectResume fits when the wording is the hard part. Its guide describes prompts for building or importing a resume, job-specific bullet-point suggestions, summary suggestions, writing tips, and AI-powered suggestions for skills. It also has a resume checker, so the guided sequence and the feedback live in the same hosted product. Its cover-letter workflow is another reason to pick it if you want guided related documents. The free guide describes writing a matching cover letter with prompts and content suggestions, though the designed cover-letter downloads sit behind the same premium boundary. ## Where Reactive Resume is a better fit Reactive Resume fits when you have the content and want a designed export without picking a premium plan. Make your template and layout choices in the editor, then export a PDF or DOCX for document use, Markdown for text workflows, or JSON for a backup that keeps the structured resume data. The [template selection guide](/guides/choosing-a-template) covers the template workflow. You also get control over the application itself. Reactive Resume is [MIT-licensed](/legal/license), its source is public, and you can self-host it. The hosted service stays available if you would rather not run the stack. ## Which should you choose? Choose MyPerfectResume if you want prompts, prewritten suggestions, and a dedicated resume-checking tool while you draft. Choose Reactive Resume if you already have the content and want designed exports, portable JSON, or the option to run the software yourself. Neither choice promises an application outcome. The question is whether guided content and checking tools are worth a paid workflow for formatted downloads. ## Reactive Resume limitations in this comparison Reactive Resume has no equivalent library of role-specific prewritten bullets, no step-by-step writing prompts, and no specialized resume checker. Its optional AI integration asks you to configure a provider and review whatever it suggests. If you want a hosted product that supplies the drafting prompts and the feedback in one place, MyPerfectResume has the broader built-in writing surface. ## Sources * [MyPerfectResume: use the resume builder for free](https://www.myperfectresume.com/career-center/resumes/how-to/free-resume-builder) * [MyPerfectResume pricing](https://www.myperfectresume.com/pricing) Last checked: July 28, 2026 Use Reactive Resume when you already have the content and want free PDF, DOCX, Markdown, and JSON exports. # Reactive Resume vs Novorésumé Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-novoresume Compare Reactive Resume and Novorésumé by free document limits, templates, guided writing, AI, exports, and self-hosting. Novorésumé is the stronger choice when guided design, writing advice, a content library, and its built-in assistant carry most of the drafting. Reactive Resume lets you keep several saved resume versions, without the Basic plan's document and page limits. ## Quick comparison | Consideration | Reactive Resume | Novorésumé | | ---------------- | ------------------------------------ | ------------------------------------------------------------------------ | | Saved resumes | Manage separate resume versions | Basic permits one document | | Document length | Use the length your content requires | Basic permits one page; Premium permits longer documents | | Drafting support | Direct editing and optional AI | Guided design, writing advice, content library, and integrated assistant | | Exports | PDF, DOCX, Markdown, and JSON | See Novorésumé plan and export options | Novorésumé's current Basic plan permits exactly one document, capped at one page. Its Premium plan lists 72 documents and documents up to 10 pages. The product also documents templates, a content library, real-time advice, and an integrated assistant. Reactive Resume keeps resume versions in the [dashboard](/guides/managing-resumes-from-the-dashboard) and supports [PDF, DOCX, Markdown, and JSON exports](/guides/exporting-your-resume). Its source is public under the [MIT license](/legal/license), and it runs with Docker. ## Where Novorésumé is a better fit Choose Novorésumé when its guided design, writing advice, content library, and integrated assistant are worth more to you than managing several versions in one system. Premium also fits when its larger document count and longer documents match what you need. ## Where Reactive Resume is a better fit Pick Reactive Resume to manage several saved resumes and export them as PDF, DOCX, Markdown, or JSON. You can also self-host it; see the [Docker guide](/self-hosting/docker). ## Which should you choose? Choose Novorésumé when its guided drafting tools come first and its Basic or Premium document limits fit your workflow. Choose Reactive Resume when you want several resume versions and designed exports without moving to a premium plan. ## Reactive Resume limitations in this comparison Reactive Resume has a smaller guidance and content surface. It has no equivalent to Novorésumé's content library and assistant inside a guided drafting workflow. ## Sources * [Novorésumé product and plan comparison](https://novoresume.com/) Last checked: July 28, 2026 Use Reactive Resume when you want multiple resumes and designed exports without moving to a premium plan. # Reactive Resume vs Overleaf Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-overleaf Compare Reactive Resume's visual resume builder with Overleaf's LaTeX templates, source editing, collaboration, and PDF workflow. Overleaf suits people who want to work in LaTeX source, use a large community template gallery, and collaborate on documents. Reactive Resume is for people who want to edit structured resume sections visually, without writing or debugging LaTeX. The two products use different authoring models. Overleaf is an online LaTeX editor that compiles source into documents, including CV and resume templates. Reactive Resume stores resume content as structured data and renders it through its own templates and visual controls. ## Quick comparison | Consideration | Reactive Resume | Overleaf | | ---------------- | ----------------------------------------------- | --------------------------------------------------------- | | Primary workflow | Visual resume editing with structured sections | LaTeX source editing and compilation | | Template model | Built-in resume templates and layout settings | Community CV and resume LaTeX templates | | Source control | Resume JSON export, not LaTeX source | Direct editing of LaTeX project files | | Collaboration | Resume sharing and export workflow | Project collaboration with plan-dependent limits | | Output | PDF, DOCX, Markdown, and Reactive Resume JSON | Compiled document PDFs and project source | | Free plan | Core hosted resume workflow has no premium tier | Free plan has documented collaboration and compile limits | Overleaf's [CV and résumé gallery](https://www.overleaf.com/latex/templates/tagged/cv) collects community templates, and its [plans documentation](https://docs.overleaf.com/getting-started/free-and-premium-plans) explains the differences between free and paid accounts. Reactive Resume keeps the task narrower: enter resume content, pick a template, tune its settings, and export the result. ## Where Overleaf is a better fit Use Overleaf if you want to work directly in LaTeX. It gives you control over the source document and access to a broad community template gallery. That helps when you already keep academic or technical documents in LaTeX, want to change the typesetting at the source level, or need a resume that follows a particular LaTeX template. Overleaf also has a document-collaboration workflow. Its plan pages describe collaborator and compile-time allowances, so check the limits for the plan you use. That can beat a resume-focused tool when several people work on the same LaTeX project, or when the resume belongs to a larger set of academic documents. ## Where Reactive Resume is a better fit Use Reactive Resume if you prefer a visual editor and do not want to maintain LaTeX source. It keeps common resume content in fields for profile details, experience, education, skills, projects, and other sections, then shows the result in a live preview. You can switch templates and adjust resume layout settings without touching a document class or a compilation config. Reactive Resume also has [PDF, DOCX, Markdown, and JSON exports](/guides/exporting-your-resume). The JSON export preserves resume content and settings so you can restore it later or branch another version. If you need to run the software on your own infrastructure, the project is [MIT-licensed](/legal/license) and [self-hostable](/self-hosting/docker). ## Which should you choose? Choose Overleaf if LaTeX source, community templates, or collaborative academic documents are central to how you work. Choose Reactive Resume if you want a focused visual resume builder and structured fields without a LaTeX editing workflow. Both tools produce a PDF, but the upkeep differs. With Overleaf you maintain a source document. With Reactive Resume you update resume data and template settings. ## Reactive Resume limitations in this comparison Reactive Resume has no LaTeX source editing and no Overleaf-style collaboration on academic document projects. It also does not expose the source-level typesetting control of a LaTeX template. Overleaf is the more relevant option when you need those. ## Sources * [Overleaf CV and résumé templates](https://www.overleaf.com/latex/templates/tagged/cv) * [Overleaf free and premium plans](https://docs.overleaf.com/getting-started/free-and-premium-plans) * [Overleaf plans and pricing](https://www.overleaf.com/user/subscription/plans) * [Reactive Resume: exporting your resume](/guides/exporting-your-resume) Last checked: July 28, 2026 Build from structured sections and a live preview without maintaining a LaTeX document. # Reactive Resume vs Resume.com Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-resume-com Compare two free resume builders by PDF export, accounts, templates, open-source access, portability, and self-hosting. Reactive Resume and Resume.com both let you create and download a PDF resume without a paid membership. Resume.com is a straightforward hosted builder. Reactive Resume stores resume details in structured sections and adds source access, self-hosting, and more export formats. ## Quick comparison | Consideration | Reactive Resume | Resume.com | | ------------------- | ------------------------------------------------------------------- | --------------------------------------------------- | | Free final download | PDF, DOCX, Markdown, and JSON | PDF and plain text | | Accounts | Account required for the hosted builder and saved resume management | An email is requested to save work in the dashboard | | Workflow | Structured sections, template settings, and live preview | Hosted builder with templates and saved resumes | The common ground here is the download boundary. Resume.com says its builder has no paid membership tier and that PDF and plain-text downloads are free. Reactive Resume is not a cheaper way to get a Resume.com PDF: both produce one without a premium upgrade. Reactive Resume adds [DOCX, Markdown, and JSON exports](/guides/exporting-your-resume). JSON preserves the data for backup or reuse, and Markdown helps when a plain-text document still needs some formatting. Its [public MIT license](/legal/license) and [Docker self-hosting guide](/self-hosting/docker) also let you run the application outside the hosted service. ## Where Resume.com is a better fit Resume.com fits when you want a hosted builder with a simple account-and-dashboard workflow. Its account guide says you can start a resume and then enter an email address to save it. Its free-plan help page describes professional and creative templates, editing, and online access to saved work. That is the less technical choice if you only need a browser-based editor and a free PDF or text download. There is no server to set up, no AI provider to pick, and no data export to think about beyond the finished document. ## Where Reactive Resume is a better fit Reactive Resume fits when the resume should stay portable as data as well as a document. The editor keeps sections separate from templates, so changing a template does not mean re-entering your work history or education. Deployment is your call too. Use the hosted product, read the source, or run it on your own infrastructure. For programmatic access, Reactive Resume exposes [MCP tools](/guides/using-the-mcp-server) and API capabilities. AI assistance is optional and uses a provider you configure; ordinary editing does not need it. ## Which should you choose? Choose Resume.com when you want a hosted builder with no paid membership, whose documented free downloads cover PDF and plain text. Choose Reactive Resume when you want the same free PDF plus structured data exports, optional self-hosting, or automation interfaces. Either way, you still have to check the final document for accuracy and formatting. The decision is whether a focused hosted workflow is enough, or whether you also want control over the application and your resume data. ## Reactive Resume limitations in this comparison Reactive Resume asks more of you once you use its technical options. Self-hosting means running infrastructure, and provider-configured AI means your own provider setup and possible provider charges. Its extra exports and automation tools are unnecessary if you only want to type content into a hosted builder and download a PDF. ## Sources * [Resume.com: Is Resume.com really free?](https://support.resume.com/hc/en-us/articles/360008079171-Is-Resume-com-really-free) * [Resume.com: creating an account](https://support.resume.com/hc/en-us/articles/360040199931-How-do-I-create-a-new-account) Last checked: July 28, 2026 Try Reactive Resume when self-hosting, structured exports, or automation matter alongside free PDF creation. # Reactive Resume vs Resume.io Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-resume-io Compare Reactive Resume and Resume.io by free PDF access, templates, writing tools, exports, open source, and self-hosting. Resume.io is a commercial, guided builder with sample content and a template-focused workflow. Its documented free PDF allowance is narrower: the Vancouver template, alongside TXT export. Reactive Resume includes its templates and its PDF, DOCX, Markdown, and JSON exports with no premium resume tier. ## Quick comparison | Consideration | Reactive Resume | Resume.io | | ------------------------ | ----------------------------------------------- | ------------------------------------------------- | | Free final download | PDF, DOCX, Markdown, and JSON | PDF with the Vancouver template or TXT | | Other designed templates | Included templates | Premium trial or subscription workflow | | Content support | Direct editing; optional provider-configured AI | Sample resumes, pre-generated sentences, and tips | | Deployment | Hosted use or self-hosting | Hosted service | | Pricing availability | No premium resume tier | Plans can vary by location | Resume.io's free-plan help article says a free account can build a resume and download either a PDF with the Vancouver template or a TXT file. The same article says downloading in its other designed templates, and using premium features, needs a premium trial. So the free PDF allowance is template-specific, not a claim that every Resume.io PDF download is paid. The help page also says plan availability can vary by location or differ from previous plans. Rather than trusting a quoted price, check the current account flow if plan availability matters to your decision. ## Where Resume.io is a better fit Resume.io fits when you want a commercial template experience with content help included. Its help article points to sample resumes and describes cover-letter tools with pre-generated sentences and tips. A free account can also share an online resume link and come back later to edit the document. The Vancouver template makes it workable for someone who likes that design and needs only one free PDF path. Its premium workflow suits people who want the wider template selection and related features through the hosted product. ## Where Reactive Resume is a better fit Reactive Resume fits when you want to pick from the included templates and export a designed document without a template tier in the way. Its [export guide](/guides/exporting-your-resume) covers PDF, DOCX, Markdown, and JSON. The data export keeps your structured content and settings alongside the document download. You also get source access and self-hosting. Reactive Resume is [MIT-licensed](/legal/license), and its [Docker guide](/self-hosting/docker) documents the self-hosted route. Its optional AI integration lets you configure a provider if you want help, while ordinary editing does not depend on it. ## Which should you choose? Choose Resume.io if its guided content, sample resumes, hosted workflow, and Vancouver free-PDF option match how you want to write. Choose Reactive Resume if you want its included templates, several export formats, and no premium tier on the core resume workflow. Both services can make a resume for free. What matters is whether the free download you need comes in the template and file format you plan to use. ## Reactive Resume limitations in this comparison Reactive Resume has a smaller built-in guided-content library. It has no equivalent to Resume.io's collection of sample resumes, pre-generated cover-letter sentences, and tips. Its optional AI features also require you to choose and configure a provider, which is less convenient if you want a commercial writing workflow already assembled. ## Sources * [Resume.io: using the service for free](https://help.resume.io/en/articles/3785088) Last checked: July 28, 2026 Use Reactive Resume when you want the included templates, multiple export formats, and no premium resume tier. # Reactive Resume vs Resume-Now Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-resume-now Compare Reactive Resume and Resume-Now by free export formats, guided writing, AI tools, templates, and self-hosting. Resume-Now is built around guided drafting, with content suggestions, AI writing tools, and resume analysis. Reactive Resume is built around direct editing of structured resume data and includes designed PDF and DOCX exports, with a much smaller writing-guidance surface. ## Quick comparison | Consideration | Reactive Resume | Resume-Now | | --------------------- | ------------------------------------------------- | ------------------------------------------------------------------ | | Free final download | PDF, DOCX, Markdown, and JSON | Plain-text TXT | | Designed PDF and Word | Included exports | Paid access required | | Writing workflow | Direct fields and optional provider-configured AI | Career questions, suggested bullets, and AI enhancement | | Analysis tools | No equivalent specialized checker | Resume checker, summary generator, skills generator, and AI review | | Deployment | Hosted use or self-hosting | Hosted service | Resume-Now's free-builder guide says the no-cost download is a TXT file, and that downloading with a premium template requires paid access. Its FAQ says premium file formats require an upgrade. So free creation is not the same as a designed PDF or Word document. Reactive Resume includes [PDF, DOCX, Markdown, and JSON exports](/guides/exporting-your-resume) in the core workflow. JSON is a structured backup format rather than a document you send; PDF and DOCX are the designed outputs here. ## Where Resume-Now is a better fit Resume-Now fits when you want help producing the content. Its free-builder guide walks through picking a template, importing an existing resume, answering career questions, choosing personalized content suggestions, and running an AI enhancement action. It also describes spell-check, formatting controls, and optional sections during review. The product has a larger set of related writing and analysis tools. Its public pages list an AI summary generator, a skills generator, a resume checker, and an AI review. Those help when you want suggestions and feedback before deciding what to include, rather than starting from a draft you already wrote. ## Where Reactive Resume is a better fit Reactive Resume fits when direct editing and a designed export matter more than a guided-content library. The editor keeps resume sections separate from the visual template, so you can change templates without replacing your experience, education, or skills. The [template guide](/guides/choosing-a-template) covers that selection process. Portability and deployment control come with it. Reactive Resume is [open source under the MIT license](/legal/license) and can be run by following the [self-hosting documentation](/self-hosting/docker). Its AI is provider-configured, so it stays optional rather than a required part of the editing workflow. ## Which should you choose? Choose Resume-Now if you want questions, suggestions, and a set of hosted analysis tools while drafting, and you accept the TXT-only free download. Choose Reactive Resume if you want direct control over your content and a designed PDF or DOCX export without moving to a premium tier. Both workflows still leave you to verify that every statement is accurate and that the final document suits the role. ## Reactive Resume limitations in this comparison Reactive Resume has a smaller built-in writing-guidance surface. It has no equivalent to Resume-Now's prewritten suggestions, resume checker, summary generator, skills generator, or AI review. Its optional AI path also asks you to choose and configure a provider, which is more setup than a hosted suggestion workflow. ## Sources * [Resume-Now: using the builder for free](https://www.resume-now.com/job-resources/resumes/how-to-use-our-resume-builder) * [Resume-Now home page](https://www.resume-now.com/) Last checked: July 28, 2026 Try Reactive Resume when direct editing and designed exports matter more than a large guided-content library. # Reactive Resume vs ResumeGemini Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-resumegemini Compare Reactive Resume and ResumeGemini by free PDF export, AI optimization, content examples, open source, and self-hosting. ResumeGemini offers prewritten examples and job-targeted AI suggestions while you draft. Reactive Resume gives you deployment control and your own choice of AI provider instead of a bundled optimization product. ## Quick comparison | Consideration | Reactive Resume | ResumeGemini | | ------------- | ----------------------------------------------- | --------------------------------------------------------------------- | | Writing help | Direct editing; optional provider-configured AI | Prewritten expert content and job-specific examples | | Job targeting | Manual edits or optional AI assistance | AI optimization, keyword alignment, and content tips for a target job | | PDF | PDF export | Site documents free-plan PDF download and free/premium templates | ResumeGemini describes prewritten, job-specific examples, AI recommendations, keyword alignment, and content tips for a target job. Its product page documents free and premium templates plus a free-plan resume download. That covers at least one free template and free PDF path; it does not mean every template is free. Reactive Resume supports PDF, DOCX, Markdown, and JSON exports. AI is optional and needs a provider you configure, test, and enable, and that provider account can cost extra. ## Where ResumeGemini is a better fit Choose ResumeGemini when you want a content library and job-targeted AI optimization in one drafting workflow. Its examples and suggestions help most when the first draft of the wording is the problem. ## Where Reactive Resume is a better fit Use Reactive Resume to inspect or deploy the software yourself, keep resumes as structured data, or pick your own AI provider. It also exposes authenticated API and MCP workflows for automation. ## Which should you choose? Choose ResumeGemini for built-in examples and keyword-oriented suggestions. Choose Reactive Resume for open-source access, self-hosting, and control over the AI provider and automation workflow. ## Reactive Resume limitations in this comparison Reactive Resume has no built-in library of content examples and no native keyword-optimization product. Its AI workflow also needs provider credentials before you can use it. ## Sources * [ResumeGemini product page](https://www.resumegemini.com/) * [ResumeGemini product overview](https://resumegemini.com/about-us) * [Reactive Resume: AI resume builder](/use-cases/ai-resume-builder) * [Reactive Resume: using AI](/guides/using-ai) * [Reactive Resume: API and MCP automation](/use-cases/api-mcp-resume-automation) Last checked: July 28, 2026 Use Reactive Resume when source access and deployment control matter more than integrated content examples. # Reactive Resume vs Resumod Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-resumod Compare Reactive Resume and Resumod by AI writing, role-specific samples, named tool surfaces, exports, open source, and self-hosting. Resumod suits you when you want role-specific sample categories alongside its ATS Resume Checker and AI Resume Builder. Reactive Resume gives you open-source deployment, optional bring-your-own AI, and structured resume exports. ## Quick comparison | Consideration | Reactive Resume | Resumod | | -------------- | ----------------------------------------------- | ------------------------------------------------------------- | | Content help | Direct editing; optional provider-configured AI | Role-specific sample categories and a named AI Resume Builder | | Checking tools | No equivalent built-in tool | Named ATS Resume Checker | Resumod's [product page](https://resumod.co/) lists role-specific sample categories and links to an [ATS Resume Checker](https://resumod.co/ats-resume-checker) and an [AI Resume Builder](https://resumod.co/ai-resume-builder). Those pages do not document how the tools work, what they output, or their full plan limits. Reactive Resume exports PDF, DOCX, Markdown, and JSON. Its AI is optional: you connect and enable a provider with your own credentials, and that provider can cost extra. ## Where Resumod is a better fit Choose Resumod when role-specific examples and its named ATS-checker and AI-builder tools are worth more to you than picking your own provider. ## Where Reactive Resume is a better fit Use Reactive Resume when source access, self-hosting, and a separate provider choice matter. It keeps resumes as structured data and exposes authenticated API and MCP workflows for automation. ## Which should you choose? Choose Resumod for its bundled samples and named tools. Choose Reactive Resume for configurable AI, deployment control, several export formats, and data-oriented automation. ## Reactive Resume limitations in this comparison Reactive Resume has no built-in role-specific content library and no named ATS-checker tool. Its AI features also need provider setup before they work. ## Sources * [Resumod product page](https://resumod.co/) * [Resumod AI resume builder](https://resumod.co/ai-resume-builder) * [Resumod ATS Resume Checker](https://resumod.co/ats-resume-checker) * [Reactive Resume: AI resume builder](/use-cases/ai-resume-builder) * [Reactive Resume: using AI](/guides/using-ai) * [Reactive Resume: API and MCP automation](/use-cases/api-mcp-resume-automation) Last checked: July 28, 2026 Try Reactive Resume when configurable provider and deployment choices suit you better than role-specific samples and named tool surfaces. # Reactive Resume vs Rezi Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-rezi Compare Reactive Resume and Rezi by free limits, ATS scoring, keyword targeting, AI writing, provider choice, and self-hosting. Rezi suits you when you want its score, keyword targeting, AI writing, interview tool, and expert-review option. Reactive Resume keeps AI optional and provider-configured, and adds open-source self-hosting plus API or MCP automation. ## Quick comparison | Consideration | Reactive Resume | Rezi | | -------------- | ---------------------------------------- | ----------------------------------------- | | AI | Optional; connect your own provider | Integrated AI writing and editing | | Targeting | Manual edits or optional AI assistance | Rezi Score and keyword-targeting features | | Review | No specialist human-review service | Expert resume-review option | | Interview help | No equivalent built-in interview tool | AI Interview feature | | Free limits | Core hosted workflow has no premium tier | One resume and three PDF downloads | | Deployment | Hosted use or self-hosting | Hosted service | Rezi's pricing page documents the free plan's one-resume and three-PDF-download limits, plus integrated AI writing and editing. It also lists Rezi Score, keyword targeting, AI Interview, and an expert resume-review option. Those are documented product features, not a promise of ATS passage, interviews, or hiring results. Reactive Resume's AI is optional and bring-your-own-provider: you configure the credentials, and provider use can cost extra. It has no equivalent to Rezi Score, keyword targeting, AI Interview, or expert review. ## Where Rezi is a better fit Choose Rezi when you want its score, keyword targeting, AI writing, interview practice, or expert review in one product. Its documented free limits are also worth weighing if you only need one resume and up to three PDF downloads. ## Where Reactive Resume is a better fit Reactive Resume is the better choice when provider choice, open-source access, and self-hosting matter more than a built-in score. It also has authenticated API and MCP workflows for resume and application automation. ## Which should you choose? Choose Rezi for a scoring and review-oriented workflow. Choose Reactive Resume for deployment control, configurable AI, structured exports, and API or MCP automation. ## Reactive Resume limitations in this comparison Reactive Resume has no equivalent to Rezi's score, keyword targeting, interview tool, or human review. Its AI features need provider setup and may cost extra through the provider. ## Sources * [Rezi pricing and feature comparison](https://www.rezi.ai/pricing) * [Rezi official product summary](https://www.rezi.ai/ai-llm-info) * [Reactive Resume: AI resume builder](/use-cases/ai-resume-builder) * [Reactive Resume: using AI](/guides/using-ai) * [Reactive Resume: API and MCP automation](/use-cases/api-mcp-resume-automation) Last checked: July 28, 2026 Use Reactive Resume when provider choice, open source, self-hosting, and API or MCP automation matter more than an integrated ATS score. # Reactive Resume vs Zety Source: https://docs.rxresu.me/comparisons/reactive-resume-vs-zety Compare Reactive Resume and Zety by free downloads, guided writing, resume checks, templates, open source, and self-hosting. Zety is a guided resume builder with writing assistance, a cover-letter workflow, a resume check, and job-matching tools. Reactive Resume is an open-source editor with designed PDF and DOCX exports, and it has no equivalent prewritten guidance or job matching. ## Quick comparison | Consideration | Reactive Resume | Zety | | ------------------- | ----------------------------------------------- | --------------------------------------------------------------- | | Free final download | PDF, DOCX, Markdown, and JSON | Plain-text TXT | | PDF and Word | Included exports | Paid formats | | Guidance | Direct editing; optional provider-configured AI | Guided builder, templates, and writing resources | | Related job tools | No equivalent job matching | Resume Check and Instant Job Matches listed in the free package | | Deployment | Hosted use or self-hosting | Hosted service | Zety's pricing page lists a TXT download in its free package. Its plan comparison names PDF, Word, and TXT among its download formats and shows TXT only for the free package. So the free package can write and export text, while a designed PDF or Word download sits in the paid workflow. Reactive Resume includes [PDF, DOCX, Markdown, and JSON exports](/guides/exporting-your-resume) in its core resume workflow. That difference is about document formats. Neither product can tell you how an employer or an applicant-tracking system will handle the result. ## Where Zety is a better fit Zety fits when you want guidance and related job-search tools in one hosted product. Its pricing page lists a resume builder, templates, a cover-letter builder, cover-letter templates, a resume check, and instant job matches. The wider Zety site puts resume help and examples alongside the builder. That suits you if you want help choosing words, a matching cover letter, or a separate check before you export. The free package's TXT download is also enough when you paste content into a text form instead of attaching a formatted document. ## Where Reactive Resume is a better fit Reactive Resume fits when you want to download a designed PDF or DOCX without upgrading. Its templates render structured resume sections, and the [template guide](/guides/choosing-a-template) covers how to pick one. JSON export keeps your structured data for backup or reuse, separately from the final PDF or DOCX. You also control where it runs. The source is public under the [MIT license](/legal/license), and the [Docker self-hosting guide](/self-hosting/docker) covers running your own instance. AI help is optional and uses a provider you configure. ## Which should you choose? Choose Zety if you want a hosted builder with guided writing, a resume check, cover-letter tools, and job matching, and TXT is enough for the free export. Choose Reactive Resume if a free designed PDF or DOCX, structured exports, and the option to self-host matter more than those guidance tools. Either way, check the final wording and layout yourself. The tools help you prepare a resume; they do not decide the hiring result. ## Reactive Resume limitations in this comparison Reactive Resume has no built-in library of prewritten writing guidance, no dedicated resume-check product, and no job matching. Its optional AI route needs provider setup, and self-hosting means running a server. Zety is more convenient if you want those hosted services next to the builder and do not need a free PDF or Word export. ## Sources * [Zety pricing](https://zety.com/pricing) Last checked: July 28, 2026 Try Reactive Resume when free PDF and DOCX exports matter more than guided writing and job-matching tools. # Project architecture Source: https://docs.rxresu.me/contributing/architecture How the Reactive Resume monorepo is laid out, the runtime boundaries between the web and server apps, and the package ownership model. Reactive Resume is a pnpm/Turborepo monorepo. The product runs as one deployed Node.js process, while the source is split into a full-stack web app, a server adapter, and focused internal packages. Internal packages are source-consumed through their `package.json` export maps. Import package subpaths, not another workspace's private `src` files. *** ## Runtime shape ```mermaid theme={null} flowchart TD Browser["Browser"] --> WebRoutes["apps/web routes"] WebRoutes --> ORPCClient["oRPC client"] ORPCClient --> RPC["/api/rpc"] subgraph NodeProcess["Node process"] Server["apps/server Hono adapter"] API["packages/api feature routers"] Auth["packages/auth"] MCP["packages/mcp"] PDFServer["@reactive-resume/pdf/server"] end Server --> RPC RPC --> API Server --> Auth Server --> MCP API --> PDFServer API --> DB["packages/db"] API --> Storage["File system or S3-compatible storage"] DB --> Postgres["PostgreSQL"] ``` `apps/web` owns the TanStack Start experience. `apps/server` owns the production Hono process and mounts RPC, auth, OpenAPI, MCP, static uploads, schema JSON, and the built web app. *** ## Workspace map | Workspace | Ownership | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------- | | `apps/web` | TanStack Start routes, web features, browser PDF.js preview/viewer code, PWA setup, oRPC browser client | | `apps/server` | Hono route composition, production HTTP adapters, MCP transport, OpenAPI/well-known handlers, static file serving, startup checks | | `packages/api` | oRPC procedures and feature-owned business behavior under `src/features/*` | | `packages/auth` | Better Auth config, auth helpers, and exported auth types | | `packages/db` | Drizzle client and schema; root `migrations/` stores generated migrations | | `packages/env` | Server environment validation and root `.env` loading | | `packages/schema` | Zod schemas and typed resume/page/template models | | `packages/resume` | Pure resume-domain helpers, including JSON Patch behavior and network icon mapping | | `packages/pdf` | React PDF document, template primitives, templates, font registration, and browser/server generation adapters | | `packages/docx` | DOCX export generation | | `packages/mcp` | MCP tools, prompts, resources, server card, and tool metadata | | `packages/ui` | Shared Base UI/shadcn-style primitives and hooks | | `packages/ai` | AI provider types, prompts, resume parsing/sanitization helpers, and model-facing tool contracts | | `packages/import` | Resume importers | | `packages/fonts` | Font metadata | | `packages/email` | Email transport and templates | | `packages/utils` | Narrow cross-cutting utilities with explicit export subpaths | | `packages/config` | Shared development configuration | | `tooling` | Development-only scripts and repo tooling | *** ## Boundary rules * Use `@reactive-resume/*` package exports for cross-workspace imports. * Do not import another workspace through `apps/**`, `packages/**`, `@reactive-resume/*/src/**`, or a TypeScript path alias to another workspace's `src`. * Keep browser-only code in web features or explicit browser subpaths. * Keep server-only code in server packages or explicit server subpaths. * Keep environment-neutral domain packages free of DB, HTTP, DOM, and app imports. * Add public package exports deliberately. Wildcard exports are reserved for leaf-style public surfaces such as UI components/hooks and schema resume files. The checks are executable: ```bash theme={null} pnpm exec turbo boundaries pnpm exec biome check biome.json turbo.json tooling/grit/no-cross-workspace-src-imports.grit apps/web/tsconfig.json apps/*/turbo.json packages/*/turbo.json ``` *** ## Feature placement When adding code, choose the owner by behavior: | Change | Put it here | | ---------------------------------------------------------- | -------------------------------------------------------------------------------- | | Route, loader, route-level server handler, or web workflow | `apps/web/src/routes` plus `apps/web/src/features/` | | API procedure or authenticated business behavior | `packages/api/src/features/` | | Pure resume data logic | `packages/resume` | | Resume schema or template list shape | `packages/schema` | | React PDF template/rendering behavior | `packages/pdf` | | PDF.js canvas/viewer UI | `apps/web/src/features/resume` | | DOCX export behavior | `packages/docx` | | MCP tool/prompt/resource behavior | `packages/mcp` | | Shared UI primitive/hook | `packages/ui` | | Cross-cutting helper | Prefer a domain package first; otherwise add an explicit `packages/utils` export | *** ## Web layout `apps/web/src/routes` stays route-owned. Route files handle URL shape, loaders, redirects, metadata, and SSR flags. Domain UI and browser-heavy implementation code lives under `apps/web/src/features`. Current feature areas include resume preview/export/public pages, command palette, auth, settings, theme, locale, and user menu behavior. Generic app-local components remain in `apps/web/src/components`; shared reusable primitives live in `packages/ui`. Dialog runtime state is centralized in `apps/web/src/dialogs/store.ts`, while dialog schemas and renderers are registered by domain under `apps/web/src/dialogs/{auth,api-key,resume}`. *** ## API layout `packages/api/src/routers/index.ts` exports the top-level oRPC contract. Feature modules under `packages/api/src/features/*` own their procedure modules, services, helpers, tests, and public package exports. Avoid reintroducing technical-layer folders such as `services/` or `helpers/` at the package root. If a helper is used by one feature, keep it in that feature. If it becomes shared, name the shared capability explicitly and export it intentionally. *** ## PDF and export boundaries `packages/pdf` owns React PDF generation: * `@reactive-resume/pdf/browser` creates browser PDF blobs. * `@reactive-resume/pdf/server` creates server PDF files. * Template code stays under `packages/pdf/src/templates`. Localized section-title resolution stays in the caller because it depends on web/server locale context. PDF.js preview and viewer code stays in `apps/web/src/features/resume`, not in `packages/pdf`. DOCX export generation lives in `packages/docx`. *** ## MCP boundary MCP implementation lives in `packages/mcp`. It exposes canonical unprefixed tool names such as `list_resumes`, `read_resume`, and `apply_resume_patch`. The server process imports MCP from `@reactive-resume/mcp` and injects the in-process oRPC router client. It must not import MCP code from `apps/web/src`. # Development setup Source: https://docs.rxresu.me/contributing/development Set up a local development environment for Reactive Resume with pnpm, Docker services, environment variables, and the web and server apps. **Prerequisites**: - [Node.js](https://nodejs.org/) v24 - [pnpm](https://pnpm.io/) v11.21.0 - [Docker](https://docs.docker.com/get-docker/) and Docker Compose - [Git](https://git-scm.com/) These steps set up Reactive Resume for local development, whether you're contributing to the project or customizing it for yourself. *** ## Setting up your development environment ```bash theme={null} git clone https://github.com/amruthpillai/reactive-resume.git cd reactive-resume ``` Install [pnpm](https://pnpm.io/installation) directly, then install the project dependencies: ```bash theme={null} pnpm install ``` If you want to run the app directly on your machine with `pnpm dev`, start only the infrastructure services: ```bash theme={null} docker compose -f compose.dev.yml up -d postgres redis seaweedfs seaweedfs_create_bucket ``` This starts the following infrastructure services: * **PostgreSQL** — Database (port 5432) * **Redis** — AI Agent workspace streams/state (port 6379) * **SeaweedFS** — S3-compatible storage (port 8333) **From v5.1.0 onwards** — PDF generation now runs entirely in the browser via `@react-pdf/renderer`, so no Browserless or Chromium container is required for development. `compose.dev.yml` can also run the app in a development container with `docker compose -f compose.dev.yml up -d`. Use the service-filtered command above when you want local editor tooling and `pnpm dev` on the host. Wait for all services to be healthy before proceeding. Check with `docker compose -f compose.dev.yml ps`. Copy `.env.example` to `.env.local` in the project root: ```bash theme={null} cp .env.example .env.local ``` Then edit `.env.local` as needed. For local development on the host, set at minimum: ```bash theme={null} # Application PORT=3000 SERVER_PORT=3001 APP_URL=http://localhost:3000 # Database DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres # Authentication AUTH_SECRET=development-secret-change-in-production # Storage (SeaweedFS) S3_ACCESS_KEY_ID=seaweedfs S3_SECRET_ACCESS_KEY=seaweedfs S3_ENDPOINT=http://localhost:8333 S3_BUCKET=reactive-resume S3_FORCE_PATH_STYLE=true # Email (Mailpit for local development) SMTP_HOST=localhost SMTP_PORT=1025 SMTP_FROM="Reactive Resume " # AI Agent workspace and saved AI providers REDIS_URL=redis://localhost:6379 ENCRYPTION_SECRET=change-me-to-a-secure-agent-secret-in-production ``` **Email testing**: The development stack includes [Mailpit](https://mailpit.axllent.org/). Emails the app sends are captured there and viewable at [http://localhost:8025](http://localhost:8025), so nothing reaches a real address during development. The server startup path runs migrations before serving traffic. To apply migrations manually without starting the app, load `.env.local` with `dotenvx` because Drizzle Kit reads directly from `process.env`: ```bash theme={null} dotenvx run -f .env.local -- pnpm run db:migrate ``` ```bash theme={null} dotenvx run -f .env.local -- pnpm run dev ``` Your local Reactive Resume instance will be available at [http://localhost:3000](http://localhost:3000). *** ## Available scripts The scripts you will use most during development: ### Development | Command | Description | | --------------------------------------- | ------------------------------------------------------ | | `dotenvx run -f .env.local -- pnpm dev` | Start the web and server development processes | | `pnpm build` | Build the production web bundle and server bundle | | `pnpm start` | Start the built production server | | `pnpm typecheck` | Run TypeScript type checking | | `pnpm test` | Run Vitest across workspaces | | `pnpm exec biome check .` | Run a non-mutating Biome check | | `pnpm check` | Run Biome with write/fix behavior (`--write --unsafe`) | | `pnpm exec turbo boundaries` | Check workspace/package boundary rules | ### Database | Command | Description | | --------------------------------------------------- | -------------------------------------------- | | `dotenvx run -f .env.local -- pnpm run db:generate` | Generate migration files from schema changes | | `dotenvx run -f .env.local -- pnpm run db:migrate` | Apply pending migrations | | `dotenvx run -f .env.local -- pnpm run db:studio` | Open Drizzle Studio (database GUI) | ### Internationalization | Command | Description | | ------------------------- | -------------------------------------- | | `pnpm run lingui:extract` | Extract translatable strings from code | ## Understanding the project structure ``` reactive-resume/ ├── apps/ │ ├── web/ # TanStack Start routes, web features, and browser UI │ └── server/ # Hono production server, HTTP adapters, static serving ├── packages/ │ ├── api/ # oRPC features and business behavior │ ├── auth/ # Better Auth configuration and helpers │ ├── db/ # Drizzle client and schema │ ├── docx/ # DOCX export generation │ ├── mcp/ # MCP tools, prompts, resources, and metadata │ ├── pdf/ # React PDF rendering and PDF generation adapters │ ├── resume/ # Pure resume-domain helpers │ ├── schema/ # Zod schemas and typed models │ ├── ui/ # Shared Base UI/shadcn-style primitives │ └── ... ├── tooling/ # Development-only scripts and repository tooling ├── migrations/ # Generated database migrations ├── docs/ # Documentation └── data/ # Local development data and uploads ``` *** ## Working with the database ### Viewing the database Use Drizzle Studio to explore and manage your database: ```bash theme={null} dotenvx run -f .env.local -- pnpm run db:studio ``` This opens a web-based GUI at [https://local.drizzle.studio](https://local.drizzle.studio). ### Making schema changes 1. Edit the schema in `packages/db/src/schema/*` 2. Generate a migration: ```bash theme={null} dotenvx run -f .env.local -- pnpm run db:generate ``` 3. Apply the migration: ```bash theme={null} dotenvx run -f .env.local -- pnpm run db:migrate ``` Always review generated migrations before applying them, especially when working with existing data. *** ## Working with translations Reactive Resume uses [Lingui](https://lingui.dev/) for internationalization. ### Adding translatable text Use the `t` macro for strings or `` component for JSX: ```tsx theme={null} import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; // For plain strings const message = t`Hello, World!`; // For JSX content Welcome to Reactive Resume; ``` ### Extracting translations After adding new translatable text, extract them to the locale files: ```bash theme={null} pnpm run lingui:extract ``` Translation files live in `apps/web/locales`, in `.po` format. *** ## Code quality ### Linting & formatting Uses [Biome](https://biomejs.dev/) for linting, formatting, import organization, and Tailwind class sorting: ```bash theme={null} # Non-mutating check pnpm exec biome check . # Project script with write/fix behavior pnpm check ``` ### Type checking Run TypeScript type checking: ```bash theme={null} pnpm run typecheck ``` Configure your IDE to use Biome for formatting and lint diagnostics. The repo uses tabs, double quotes, 120-column lines, and organized import groups. *** ## Troubleshooting The Vite web server uses `PORT` (default `3000`), and the Hono server uses `SERVER_PORT` (default `3001`). Either stop the conflicting process or choose alternate ports: ```bash theme={null} PORT=3002 SERVER_PORT=3003 dotenvx run -f .env.local -- pnpm dev ``` Ensure Docker containers are running: ```bash theme={null} docker compose -f compose.dev.yml ps docker compose -f compose.dev.yml up -d ``` Check that PostgreSQL is healthy and accessible on port 5432. Verify SeaweedFS is running and the bucket exists: ```bash theme={null} docker compose -f compose.dev.yml logs seaweedfs docker compose -f compose.dev.yml logs seaweedfs_create_bucket ``` If the bucket wasn't created, restart the bucket creation service: ```bash theme={null} docker compose -f compose.dev.yml restart seaweedfs_create_bucket ``` The route tree may need regeneration. Run the dev server which auto-generates routes: ```bash theme={null} dotenvx run -f .env.local -- pnpm run dev ``` Or run type checking to see specific errors: ```bash theme={null} pnpm run typecheck ``` *** ## Next steps How the project and codebase are structured. View the source code and contribute to the project. # Contributing translations Source: https://docs.rxresu.me/contributing/translations Contribute translations for Reactive Resume through Crowdin by joining the project, proposing strings, requesting new languages, and syncing updates. Reactive Resume is used all over the world. If you speak a language other than English, you can help by contributing translations. *** ## How translations work Reactive Resume uses [Crowdin](https://crowdin.com/) as its localization management platform. Crowdin gives translators an interface for contributing translations without writing code or editing files directly. The Reactive Resume Crowdin project is available at [https://crowdin.com/project/reactive-resume](https://crowdin.com/project/reactive-resume). Once translations are submitted and approved on Crowdin, they are automatically synced to the codebase and will be available in the next release of the app. *** ## Updating catalogs in a checkout The PDF renderer uses a generated subset of the same translations for default section headings. Run `pnpm pdf:translations` after editing or syncing the PO catalogs. The root `pnpm lingui:extract`, `pnpm check`, and `pnpm build` commands also regenerate this file automatically. Commit `packages/pdf/src/section-title-catalog.json` with the catalog updates. Edit the source PO files rather than the generated JSON; a tooling test checks that they stay synchronized. ## Getting started If you don't already have an account, sign up at [crowdin.com](https://crowdin.com/). You can register using your email or sign up with Google, Facebook, Twitter, GitHub, or GitLab. For detailed instructions on creating an account and getting started, see Crowdin's official [For Translators](https://support.crowdin.com/for-translators/) documentation. Navigate to the [Reactive Resume project on Crowdin](https://crowdin.com/project/reactive-resume) and click **Join** to become a contributor. From the project dashboard, click on the language you want to translate. You'll see a list of files that need translation along with the progress for each. Click on a file to open the Crowdin Editor. You'll see the source text (English) on the left and a text field for your translation on the right. - Translate the text accurately while preserving any placeholders or formatting - Use the suggestions from Translation Memory and Machine Translation as a starting point - Vote on existing translations if you agree with them Your translations are saved automatically as you work. Once reviewed, they'll be included in the next app release. *** ## Translation guidelines To maintain consistency across all translations, please follow these guidelines: ### Preserve placeholders Some strings contain placeholders like `{name}` or `{count}`. These must remain unchanged in your translation: ``` English: "Hello, {name}!" Spanish: "¡Hola, {name}!" ``` ### Keep formatting Preserve any HTML tags or markdown formatting in the source text: ``` English: "Click <1>here to continue" German: "Klicken Sie <1>hier, um fortzufahren" ``` ### Use formal or informal tone consistently Choose either formal or informal language based on what's standard for software in your language, and stick with it throughout. ### Technical terms Some technical terms (like "PDF", "URL", "JSON") are often kept in English across languages. Use your judgment based on what's common in your language's software community. *** ## Requesting a new language If your language is not listed in the Crowdin project, you can request it to be added. Before requesting a new language, please check if it's already available in the [Crowdin project](https://crowdin.com/project/reactive-resume). To request a new language: 1. Go to the [GitHub Issues](https://github.com/amruthpillai/reactive-resume/issues) page 2. Click **New Issue** 3. Select the appropriate template or create a blank issue 4. Title it something like: "Add \[Language Name] to Reactive Resume" 5. Include the language name and locale code (e.g., "Japanese - ja-JP") in the issue description. Once approved, the language will be added to Crowdin and you can begin translating. *** ## When will my translations appear? Translations submitted on Crowdin are synced to the codebase periodically. Once merged, they will be included in the next release of Reactive Resume. There may be a delay between submitting translations and seeing them live in the app. This is normal and depends on the release cycle. *** ## Tips for effective translation Crowdin often shows context, screenshots, or comments to help you understand where the text appears in the app. Review translations by other contributors and vote for accurate ones to help maintain quality. Use Crowdin's comment feature to ask about unclear strings or discuss translations with other contributors. Check the project glossary (if available) to ensure terminology is used consistently across the app. *** ## Need help? Official Crowdin documentation for translators. Report issues or request new languages. *** Thank you for helping translate Reactive Resume. # Introduction to Reactive Resume Source: https://docs.rxresu.me/getting-started Reactive Resume is a free, open-source resume builder that lets you create, update, export, and share professional resumes without accounts or paywalls. Reactive Resume Banner ## What is Reactive Resume? Reactive Resume is a free and open-source resume builder that makes it easy to create, update, and share your resume. Built with privacy as a core principle, it gives you complete control over your data. Your data stays yours. No tracking, no ads, and an open-source codebase you can read. Choose from a set of professionally designed templates. See changes instantly as you type. What you see is exactly what you'll get when you export. Download your resume as PDF, share it via a unique link, or print it directly from your browser. ## Key features An infographic of the major features of Reactive Resume Reactive Resume is licensed under MIT. You can use it for free, modify it, and even host your own instance. The entire codebase is available on [GitHub](https://github.com/amruthpillai/reactive-resume). Choose from a variety of professionally designed templates including Azurill, Bronzor, Chikorita, Ditgar, Ditto, Gengar, Glalie, Kakuna, Lapras, Leafish, Meowth, Onyx, Pikachu, Rhyhorn, and Scizor, each with its own layout and style. Format your content with bold, italic, links, lists, and more using the rich text editor, powered by Tiptap. Reactive Resume is available in multiple languages. Contribute translations to help us reach more people. Built-in dark mode support, so you can work comfortably in any lighting condition. Deploy your own instance of Reactive Resume using Docker. Keep complete control over your data and infrastructure. ## Getting started Use the hosted version, or run your own instance. Start with the hosted version, or deploy your own instance. Set up a local development environment to contribute or customize Reactive Resume. ## Tech stack | Category | Technology | | ---------------- | ------------------------------- | | Framework | TanStack Start (React 19, Vite) | | Runtime | Node.js | | Language | TypeScript | | Database | PostgreSQL with Drizzle ORM | | API | ORPC (Type-safe RPC) | | Auth | Better Auth | | Styling | Tailwind CSS | | UI Components | Base UI + shadcn-style package | | State Management | Zustand + TanStack Query | ## Community & support Star the repo, report reproducible bugs, propose features, and contribute to the project. Ask questions about setup, configuration, and using Reactive Resume. Get help and talk to other users on our subreddit. Get help and talk to other users on our Discord server. Help fund the continued development of Reactive Resume. **Need help?** Start a [GitHub Discussion](https://github.com/amruthpillai/reactive-resume/discussions/categories/q-a). GitHub Issues are reserved for reproducible bugs and actionable feature proposals. # Quickstart Source: https://docs.rxresu.me/getting-started/quickstart Sign in to the hosted version of Reactive Resume, or deploy your own self-hosted instance with Docker Compose. ## Options There are two ways to use Reactive Resume: The fastest way to get started, and the right choice for most people. Deploy your own instance and keep full control. Requires some technical knowledge. *** ## Using the cloud version The easiest way to use Reactive Resume is our cloud version at [rxresu.me](https://rxresu.me). It is free, and it will stay free. Visit [rxresu.me](https://rxresu.me) and sign up for free using your email, or sign in with your GitHub or Google account. Click the **Create Resume** button on your dashboard. Give your resume a name and select a template to get started. Use the builder to add your personal information, work experience, education, skills, projects, and anything else the resume needs. When you're ready, export your resume as a PDF or share it at its public URL. Your resume updates in real-time as you type. The preview panel shows exactly how your final PDF will look. *** ## Self-host with Docker You can deploy Reactive Resume on your own infrastructure using Docker. **From v5.1.0 onwards** — PDF generation now runs entirely client-side via `@react-pdf/renderer`. Self-hosted deployments no longer require Browserless, Chromium, or any external print service as a dependency. The `PRINTER_*` and `BROWSERLESS_*` environment variables are no longer read and can be removed from your `.env`. ### Prerequisites Before you begin, ensure you have the following installed: * [Docker](https://docs.docker.com/get-docker/) (v20.10 or higher) * [Docker Compose](https://docs.docker.com/compose/install/) (v2.0 or higher) There is no difference in features between the cloud-hosted version and the self-hosted option. Both offer the same privacy and customization. Pick whichever deployment type suits you. ### Quick deployment ```bash theme={null} git clone https://github.com/amruthpillai/reactive-resume.git cd reactive-resume ``` Create a `.env` file in the root directory with the following variables: ```bash .env theme={null} # Application APP_URL=http://localhost:3000 # Database DATABASE_URL=postgresql://postgres:postgres@postgres:5432/postgres # Authentication (generate a secure secret) AUTH_SECRET=your-secure-secret-key-here # Storage (S3-compatible via SeaweedFS) S3_ACCESS_KEY_ID=seaweedfs S3_SECRET_ACCESS_KEY=seaweedfs S3_ENDPOINT=http://seaweedfs:8333 S3_BUCKET=reactive-resume S3_FORCE_PATH_STYLE=true # AI features (optional; ENCRYPTION_SECRET for saved providers, plus REDIS_URL for the agent) REDIS_URL=redis://redis:6379 ENCRYPTION_SECRET=your-secure-encryption-secret-here ``` For production deployments, always use strong, unique values for `AUTH_SECRET`, `ENCRYPTION_SECRET`, and database credentials. ```bash theme={null} docker compose up -d ``` This starts: * **PostgreSQL** — Database for storing user data and resumes * **Redis** — Required for the AI Agent workspace * **SeaweedFS** — S3-compatible storage for file uploads * **Reactive Resume** — The main application Once all services are running, access your Reactive Resume instance at: ```text theme={null} http://localhost:3000 ``` ### Docker Compose services Here's what each service in the stack does: | Service | Port | Description | | ----------------- | ---- | ---------------------------------------------------- | | `postgres` | 5432 | PostgreSQL database for storing all application data | | `redis` | 6379 | Redis instance required by the AI Agent workspace | | `seaweedfs` | 8333 | S3-compatible object storage for file uploads | | `reactive_resume` | 3000 | The main Reactive Resume application | Saved AI provider management requires `ENCRYPTION_SECRET`, and the AI Agent workspace requires both `REDIS_URL` and `ENCRYPTION_SECRET`. Other Reactive Resume features can run without them. Agent attachments and other private objects require S3-compatible storage; local storage rejects private objects. ### Health checks All services include health checks. To verify that everything is running: ```bash theme={null} docker compose ps ``` You should see all services with a `healthy` status. *** ## Environment variables reference A complete list of the environment variables you can configure: ### Required variables | Variable | Description | Example | | -------------- | ------------------------------ | ------------------------------------- | | `DATABASE_URL` | PostgreSQL connection string | `postgresql://user:pass@host:5432/db` | | `AUTH_SECRET` | Secret key for authentication | Generate with `openssl rand -hex 32` | | `APP_URL` | Public URL of your Application | `https://rxresu.me` | ### Optional variables | Variable | Description | Default | | -------------------------------------- | ----------------------------------------------------------- | ---------------------- | | `GOOGLE_CLIENT_ID` | Google OAuth Client ID | — | | `GOOGLE_CLIENT_SECRET` | Google OAuth Client Secret | — | | `GITHUB_CLIENT_ID` | GitHub OAuth Client ID | — | | `GITHUB_CLIENT_SECRET` | GitHub OAuth Client Secret | — | | `LINKEDIN_CLIENT_ID` | LinkedIn OAuth Client ID | — | | `LINKEDIN_CLIENT_SECRET` | LinkedIn OAuth Client Secret | — | | `OAUTH_PROVIDER_NAME` | Custom OAuth Provider Name | — | | `OAUTH_CLIENT_ID` | Custom OAuth Client ID | — | | `OAUTH_CLIENT_SECRET` | Custom OAuth Client Secret | — | | `OAUTH_DISCOVERY_URL` | OIDC Discovery URL (use this OR manual URLs below) | — | | `OAUTH_AUTHORIZATION_URL` | OAuth Authorization URL (manual config) | — | | `OAUTH_TOKEN_URL` | OAuth Token URL (manual config) | — | | `OAUTH_USER_INFO_URL` | OAuth User Info URL (manual config) | — | | `OAUTH_SCOPES` | OAuth Scopes (space-separated) | `openid profile email` | | `BETTER_AUTH_API_KEY` | Better Auth dashboard API key | — | | `SMTP_HOST` | SMTP Server Host (for email features) | — | | `SMTP_PORT` | SMTP Server Port | `587` | | `SMTP_USER` | SMTP Username | — | | `SMTP_PASS` | SMTP Password | — | | `SMTP_FROM` | Default FROM address for emails | — | | `SMTP_SECURE` | Use secure SMTP connection (`true` or `false`) | `false` | | `S3_ACCESS_KEY_ID` | S3 Access Key | — | | `S3_SECRET_ACCESS_KEY` | S3 Secret Key | — | | `S3_REGION` | S3 Region | `us-east-1` | | `S3_ENDPOINT` | S3-compatible Endpoint URL | — | | `S3_BUCKET` | S3 Bucket Name | — | | `S3_FORCE_PATH_STYLE` | Use path-style URLs for S3 (set `true` for MinIO/SeaweedFS) | `false` | | `REDIS_URL` | Redis connection string for the AI Agent workspace | — | | `ENCRYPTION_SECRET` | Encryption secret for saved AI provider credentials | — | | `FLAG_DISABLE_SIGNUPS` | Disables new user signups | `false` | | `FLAG_DISABLE_EMAIL_AUTH` | Disables email/password login (SSO only) | `false` | | `FLAG_DISABLE_IMAGE_PROCESSING` | Disables image processing | `false` | | `FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI` | Allows arbitrary dynamic OAuth redirect URIs | `false` | | `FLAG_ALLOW_UNSAFE_AI_BASE_URL` | Allows unsafe/private/non-public AI provider base URLs | `false` | > **Note:** Some variables are only required for using related features (OAuth, SMTP, S3, etc.) and can be left unset if unused. > **AI features:** Saved AI provider management requires `ENCRYPTION_SECRET`, and the AI Agent workspace requires both `REDIS_URL` and `ENCRYPTION_SECRET`. Live web research depends on the selected AI provider/model supporting native web search. Keep `FLAG_ALLOW_UNSAFE_AI_BASE_URL` disabled unless this is a trusted self-hosted deployment; public HTTPS provider URLs are the safe default. > **OAuth redirect safety:** Keep `FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI` disabled unless this is a trusted self-hosted deployment. Enabling it allows dynamic OAuth clients to register any parseable redirect URI, including custom schemes, private hosts, and non-loopback `http://` URLs, which can enable phishing or token exfiltration on public or multi-tenant instances. > **Health check behavior:** `/api/health` reports status for database and storage. A failure in either dependency returns HTTP `503`. *** ## Next steps Set up a development environment to contribute or customize Reactive Resume. Learn about the project structure and architecture. **Having trouble?** Check our [GitHub Issues](https://github.com/amruthpillai/reactive-resume/issues) or reach out via [email](mailto:hello@amruthpillai.com). # Accessing the previous version Source: https://docs.rxresu.me/guides/accessing-the-previous-version Access the previous version (v4) of Reactive Resume to retrieve old resumes, and export them for import into the latest version. ## Check whether the previous version is available If you've used Reactive Resume for a while, you may have resumes saved in version 4 (v4). Access depends on whether your self-hosted instance or the hosted previous-version service is currently available. When the hosted previous version is available, its address is [https://v4.rxresu.me](https://v4.rxresu.me). Availability is not guaranteed. Self-hosted operators control their own v4 instance and backups. The [v4 to v5 migration guide](/self-hosting/migration) applies only to infrastructure they are authorized to operate. It does not authorize access to hosted databases or backups. ## When v4 is accessible Open, export, and securely back up each resume you need. Import the export into v5 as a new resume; keep the v5 version until you have compared both copies. ## Accessing your v4 resumes Go to [https://v4.rxresu.me](https://v4.rxresu.me) in your browser. Use the same account credentials you used when you originally created your resumes in v4. If you used social sign-in (Google, GitHub, etc.) in v4, use the same method to sign in. If the dashboard contains your resumes, export each one as JSON before making more changes. ## Migrating to the new version If you'd like to move your resumes to the latest version of Reactive Resume, you can export them from v4 and import them into the new version: 1. In v4, open the resume you want to migrate 2. Export it as a JSON file 3. In the new version at [https://rxresu.me](https://rxresu.me), create a new account or sign in 4. Use the import feature to upload your JSON file (select the "Reactive Resume v4 (JSON)" option) Import creates a separate resume. It should not be used to replace a newer v5 copy until you have compared both versions. ## When hosted v4 or a resume is unavailable Only an authorized hosted service operator can determine whether a source snapshot exists. Open a GitHub issue without including resume contents, account credentials, reset links, or other private data. A useful request identifies the approximate time of the missing edits, the sign-in method, and whether the resume is missing or merely not visible. Recovery is handled per owner. Before accessing content, the operator must record a private case with source snapshot time, owner verification, source-to-target mapping, target resume ID, content hashes, and proposed outcome. A matching email address, username, or resume title alone is not proof of ownership. Default recovery result is a private JSON export delivered through an approved channel to a verified recipient. Old-only or divergent content must remain a separate copy; it must not overwrite a current v5 resume. If no source snapshot is available, the factual outcome is that the records cannot be recovered from the service. Local tooling cannot recreate missing source data. An empty workspace with successful create responses or name conflicts can instead be a listing or account-mapping problem. That requires a separate session, create, list, and reload diagnosis; a v4 recovery export does not resolve it. ## Questions or issues? If you run into problems accessing v4, or have questions about migrating your resumes, open an issue on [GitHub](https://github.com/amruthpillai/reactive-resume/issues). # Adding a cover letter Source: https://docs.rxresu.me/guides/adding-a-cover-letter Learn how to create a cover letter as a custom section in Reactive Resume, format it professionally, and place it on a separate page. A cover letter goes alongside your resume when you apply for a job. It introduces you to the employer, points to your relevant qualifications, and explains why you fit the position. In Reactive Resume you write one as a custom section, so you control its formatting and where it appears. ## Why include a cover letter? * It shows genuine interest in the position * You can tailor your message to each employer and role * You have room to address career changes or gaps in your resume * It demonstrates that you write clearly and professionally ## Creating a cover letter section Navigate to your resume and open it in the builder. In the left sidebar, scroll down to find the **Custom Sections** area at the bottom. Click Add a new custom section to open the section creation dialog. In the dialog: - Enter a **Title** for your section (e.g., "Cover Letter" or "Cover Letter - \[Company Name]") - Select **Cover Letter** from the **Type** dropdown - Click **Create** to add the section In your new cover letter section, click Add a new item to create your cover letter. ## Formatting your cover letter A cover letter has two main fields: ### Recipient field The **Recipient** field is where you enter the recipient's information. This typically includes: * Date (optional) * Hiring manager's name * Their job title * Company name * Company address Use line breaks to format the address block. For example: ``` January 31, 2026 Jane Smith Senior Hiring Manager Acme Corporation 123 Main Street, Suite 400 New York, NY 10001 ``` ### Content field The **Content** field is where you write the body of your cover letter. Include: * **Salutation**: "Dear Ms. Smith," or "Dear Hiring Team," * **Opening paragraph**: State the position you're applying for and how you learned about it * **Body paragraphs**: Highlight relevant experience, skills, and achievements * **Closing paragraph**: Express enthusiasm and include a call to action * **Sign-off**: "Sincerely," followed by your name The recipient and content are both rendered directly on your resume, without a section header. ## Using fullscreen mode for writing The rich text editor can expand to fill the screen when you want to write without distraction: Click on your cover letter item in the sidebar to open the edit dialog. In either the Recipient or Content field, click the **expand icon** (arrows pointing outward) in the bottom-right corner of the editor. The editor expands to nearly fill your screen, with every formatting tool still available. Click the **collapse icon** or press **Escape** to return to the normal view. ## Formatting options The rich text editor supports: * **Text styling**: Bold, italic, underline, strikethrough, highlight * **Headings**: H1 through H6 (though typically not needed in a cover letter) * **Alignment**: Left, center, right, or justified text * **Lists**: Bullet points and numbered lists * **Links**: Add hyperlinks to your portfolio or LinkedIn ## Exporting the cover letter separately You do not need to move the cover letter to a specific page to send it on its own. When you download your resume, the download dialog gives you a **Resume** tab and a **Cover letter** tab, so you can export either document as a standalone PDF, DOCX, or Markdown file. See [Exporting your resume](/guides/exporting-your-resume) for the full workflow. ## Moving your cover letter to a separate page If you also want the cover letter to appear on its own page inside the combined preview or the public resume view, place it on a new page: In the right sidebar, go to the **Layout** section and add a new page to your resume. Use the **Move to** feature to relocate your cover letter section to the second page. See [Moving items between sections](/guides/moving-items-between-sections) for detailed instructions on how to move sections between pages. Check the preview to confirm your cover letter appears on its own page and is formatted the way you want. ## Tips for effective cover letters **Keep it concise**: Aim for 250-400 words. Recruiters spend about one minute reading cover letters. **Tailor each letter**: Customize your cover letter for each application. Reference specific job requirements and company values. **Use the same styling**: Your cover letter inherits the fonts and colors from your resume template, so both documents match. **Proofread carefully**: Spelling and grammar errors can disqualify your application. Review your letter before exporting. ## Managing multiple cover letters Since cover letters are custom sections, you can: * Create multiple cover letter sections for different job applications * Name each section descriptively (e.g., "Cover Letter - Google", "Cover Letter - Meta") * Show or hide sections as needed when exporting * Duplicate sections to use as templates for new applications # AI Agent tools Source: https://docs.rxresu.me/guides/ai-agent-tools Reference for the tools the Reactive Resume AI Agent can call to read, edit, patch, and preview resume drafts inside an isolated workspace. The AI Agent workspace has a fixed set of tools it can use while it chats with you. You do not call these tools directly. The agent picks them when your request needs resume data, supported provider web context, attachments, questions, or a resume patch. ## Tool activity in chat Tool activity appears inside the conversation. Some activity is collapsed by default so the chat stays readable. Applied resume patches are shown as a small inline **Patch applied** item. Open it to inspect the raw JSON payload. AI Agent chat showing an applied patch with raw JSON details ## Available tools | Tool | What it does | Example request | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | `read_resume` | Reads the current AI draft and gives the agent the resume data it can safely edit. | "What are the weakest parts of this resume?" | | `web_search` | Uses the selected provider's native web search when that provider/model supports it. | "Research this company and adjust the summary for its product area." | | `read_attachment` | Reads extracted text from attached plain text, Markdown, or JSON files. Other supported attachments, such as images or PDFs, are passed to the model when the selected provider can use them. | "Use the attached notes to update the keywords." | | `ask_user_question` | Shows a question card with answer choices when the agent needs your decision. | "Ask me before changing the career narrative." | | `apply_resume_patch` | Applies a JSON Patch to the AI draft and stores a rollback snapshot. | "Change the visible name to Amruth Pillai." | ## Resume patches Resume patches are rooted at the resume data object. For example, the visible resume name is patched at `/basics/name`. When a patch is applied: * the AI draft updates immediately; * the raw JSON Patch is available from the **Patch applied** details; * a snapshot is stored so the draft can be restored to the state before that patch; * the resume preview refreshes to show the updated draft. Restoring an older patch rolls back that patch and any patches applied after it. If the resume changed after the latest agent patch, restore or apply can fail with a version conflict. In that case, ask the agent to retry from the latest draft. ## Web access Live web research is handled only by the selected AI provider's native web search tool. When the provider/model supports it, the agent can use `web_search` for current company, industry, role, or URL-based context. Provider-native `web_search` is not JSearch and does not restore the removed structured job-listings experience. It supplies web context to the agent; it does not provide a structured job-results API or guarantee that a provider/model can search. When the provider/model does not support native web search, the agent still works for normal resume editing. If you ask it to browse, search the web, fetch a URL, or use current online context, it should tell you that live web research is unavailable with the selected provider/model and ask you to paste or attach the relevant content instead. For a controlled workflow that works without live research, follow [Tailor a resume to a supplied job description](/guides/using-ai-agent#tailor-a-resume-to-a-supplied-job-description). Configure, test, and enable providers as described in [Using artificial intelligence](/guides/using-ai). For self-hosted deployments: * app-owned URL crawling is not available; * web access depends on the selected provider/model supporting native web search; * unsafe/private AI provider base URLs require `FLAG_ALLOW_UNSAFE_AI_BASE_URL=true`, which should only be used on trusted self-hosted deployments. ## Attachments Attach files from the chat composer when the agent needs extra context, such as: * a job description PDF; * a portfolio brief; * a screenshot; * a plain text note with constraints. Self-hosted deployments need S3-compatible storage for private agent attachments. Local filesystem storage rejects private objects. ## Good prompts for tool use Use direct prompts that tell the agent what context to use and how cautious to be: * "Research this role, identify the most important keywords, and apply a conservative patch." * "Read the attached job description and ask me before changing anything outside the summary." * "Compare my current projects against this company page and suggest only truthful wording." * "Apply a patch for the visible resume name, then show me what changed." ## When tools are unavailable Tool use can be limited by the selected provider, deployment configuration, or thread state. * A deleted provider makes the thread read-only; a disabled or untested provider blocks new agent runs until it is enabled and tested again. * A deleted working resume makes the thread read-only. * Archived threads cannot receive new messages. * Live web research is unavailable when the selected provider/model does not support native web search. * Attachments may fail if private object storage is not configured. # Checking service status Source: https://docs.rxresu.me/guides/checking-service-status Check the current uptime and incident status for Reactive Resume's hosted servers, and see what to do when the service is down or slow. ## Status page You can check the health of Reactive Resume's servers at any time on the status page: View real-time server metrics including uptime, CPU usage, memory usage, and more. The status page shows: * **Uptime**: How long the servers have been running without interruption * **CPU Usage**: Current processor utilization * **Memory Usage**: RAM consumption across services * **Response Times**: How quickly the servers are responding to requests *** ## What to do if servers are down If the servers are under high load or unreachable: Visit [status.rxresu.me](https://status.rxresu.me) to confirm if there's an ongoing issue. The page will show you the current state of all services. If the servers are under heavy load, wait a while and try again. Peak usage times can cause temporary slowdowns. Reactive Resume is a **free, open-source service** used by thousands of people worldwide. During peak times, the servers may experience higher than usual load. For major outages or planned maintenance, announcements may be posted on our [GitHub repository](https://github.com/amruthpillai/reactive-resume). *** ## A note on server capacity Reactive Resume is a **free service** that runs on limited server resources. As an open-source project maintained by a single developer, it's not feasible to invest in powerful dedicated servers without community support. Thousands of people use the service every day. Because it is free and has no venture funding behind it, server capacity stays constrained. If Reactive Resume is useful to you and you want to help keep the servers running (and maybe scale them up), consider supporting the project. *** ## Support the project Donations go directly toward server costs, better infrastructure, and keeping Reactive Resume free for everyone. Support Reactive Resume's development and server costs through Open Collective. Every contribution helps keep the service running. Make a single contribution of any amount to help with immediate server costs. Become a backer with a monthly contribution to provide sustainable support. *** ## Self-hosting as an alternative If you need guaranteed uptime, or want to avoid the limits of a shared server, you can self-host Reactive Resume on your own infrastructure. Learn how to deploy Reactive Resume on your own servers using Docker. Self-hosting gives you full control over your data and infrastructure, availability that depends only on your own server capacity, and no resources shared with other users. # Choosing a template Source: https://docs.rxresu.me/guides/choosing-a-template Compare the built-in Reactive Resume templates, preview each layout, and switch between them from the builder to pick the best design for your resume. Reactive Resume includes many templates, each with its own design. This guide covers how they differ and how to switch between them. ## How to change your template You can change templates at any time without losing your content. Navigate to your Dashboard and click on the resume you want to edit. Screenshot of your resumes dashboard showing all your resume In the resume builder, look for the right sidebar. This is where you'll find all the design and layout options. In the right sidebar, find and click on the **Template** section to expand it. Screenshot of the template section in the right sidebar Browse the available templates and click the one you want. Your resume updates immediately. Screenshot of selecting a new template from the gallery After changing the template, review your resume in the live preview. You may want to adjust spacing, colors, or layout to optimize for the new design. Screenshot of the resume with a new template applied Different templates may display your content differently. Some templates work better with shorter content, while others are designed to handle more detailed information. ## Tips for choosing the right template Different industries have different expectations: * **Creative fields** (design, marketing, arts): Templates with more visual flair like Gengar or Pikachu * **Corporate/Traditional** (finance, law, consulting): Clean, minimal templates like Onyx or Ditto * **Tech/Startups**: Modern, balanced templates like Chikorita or Leafish If you have a lot of experience to fit, choose a template that uses space efficiently. For shorter resumes, templates with more white space can make your content feel more substantial. Your resume is part of your personal brand. Choose a template that reflects your personality while remaining professional and appropriate for your target roles. Don't choose a template based on how it looks empty. Fill in your actual content and see how it flows across pages. What looks great with sample data might not work as well with your specific information. *** ## Available templates Each template can be customized further with your choice of colors, fonts, and layout options. All templates support the same features and sections. They differ only in how they present your information.
Azurill template preview Bronzor template preview Chikorita template preview Ditto template preview Ditgar template preview Gengar template preview Glalie template preview Kakuna template preview Lapras template preview Leafish template preview Meowth template preview Onyx template preview Pikachu template preview Rhyhorn template preview Scizor template preview
*** ## Customizing your template After selecting a template, you can adjust: | Setting | Description | | -------------- | ------------------------------------------------------------ | | **Colors** | Change the primary color scheme to match your personal brand | | **Typography** | Choose from various Google Fonts for headings and body text | | **Layout** | Adjust sidebar width, section order, and page margins | | **Spacing** | Fine-tune gaps between sections and elements | # Creating an account Source: https://docs.rxresu.me/guides/creating-an-account Sign up for a Reactive Resume account with email and password or social sign-in from Google or GitHub so you can start building and saving resumes. Head over to [https://rxresu.me](https://rxresu.me) and click on the Get Started button. You should see a link that says Don't have an account? Create one now →. Click on that link to go to the sign up page and you should see a form. Complete the sign up form with the following information: * **Name**: Your full name * **Email Address**: A valid email address you have access to. * **Username**: Choose a unique username (this will be used in your public resume URLs) * **Password**: Create a strong password Make sure to choose a username you're happy with, as it will be part of your public resume URL (e.g., `rxresu.me/your-username/resume-slug`). After filling in all the required fields, click the **Sign up** button. You will be signed in immediately and can start using Reactive Resume right away. No email verification is required to get started, but verifying your email is strongly recommended for account security. Email verification is optional, but strongly recommended. Verifying your email: * confirms you have access to the address on the account * lets you reset your password if you forget it You can verify your email at any time from your account settings. Look for the verification prompt in your dashboard or navigate to **Settings → Profile**. Click on **Continue** and you should be taken to your Dashboard, where you can: * Create your first resume * Import an existing resume * Manage your account settings *** ## Account security tips Create a password that's at least 8 characters long and includes a mix of letters, numbers, and special characters. Setup two-factor authentication or passkeys on your account to add an extra layer of security. *** ## Troubleshooting If your username is already taken, try a different variation. Usernames must be unique across all users. If your email is already registered, you can use the **Forgot Password** link on the login page to reset your password and regain access to your account. Check your spam folder first. If it isn't there, request a new verification email from your account settings. # Creating your first resume Source: https://docs.rxresu.me/guides/creating-your-first-resume Create your first resume in Reactive Resume by naming it, choosing a URL slug, and opening it in the builder to start filling in your details. Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials. If you haven't created an account yet, follow the guide on [Creating an account](/guides/creating-an-account). After signing in, go to your Dashboard, where all of your resumes live. This is where you can create, import, organize, and manage multiple resumes for different roles or versions. In the Resumes Dashboard, click on the Create a new resume card to open the creation form. Create a new resume dialog with name, slug, and tags fields Fill in the resume name. This can be generic (e.g., "General Resume") or tied to the position you're applying for. If you can't think of a name yet, click the magic wand button to generate one. The Slug field is auto-filled based on the name, but you can change it to anything you like. If you choose to publicly share your resume, it will be accessible at `https://rxresu.me/{username}/{slug}`. Add any Tags you want. Think of tags like folders or labels to help organize many resumes. You can filter resumes by tags later from the Dashboard. The tag filter appears after you have at least one tag. Click **Create** to start with an empty resume, or open the split-button menu and choose **Create a Sample Resume** to start with sample content. A sample resume is useful when you want to try templates, layout controls, and exports before entering your own information. Once created, a new card for your resume will appear on the Dashboard. Click it to open the resume builder and start editing. ## What you can do next After creating your first resume, you can: * change the template in [Choosing a template](/guides/choosing-a-template); * adjust the page format in [Selecting the right page format](/guides/selecting-page-format); * download a copy in [Exporting your resume](/guides/exporting-your-resume); * organize, duplicate, lock, or delete resumes in [Managing resumes from the dashboard](/guides/managing-resumes-from-the-dashboard). # Deleting your account Source: https://docs.rxresu.me/guides/deleting-your-account Export a full archive of your Reactive Resume data from the Danger Zone, then permanently delete your account, resumes, and settings. ## Export all of your data Before you delete your account, you can download a copy of everything Reactive Resume stores for you. In the dashboard sidebar, under **Settings**, click **Danger Zone**. Reactive Resume gathers your account profile, resumes, and settings into a single archive and downloads it to your browser. Keep this archive somewhere safe. It's the easiest way to restore your resumes if you delete your account and later change your mind. ## Delete your account Deleting your account is permanent. Export a copy of your data first if you might need it later. Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials. In the dashboard sidebar on the left, under Settings, click the Danger Zone link. On the Danger Zone page, type delete into the confirmation input. The Delete Account button will stay disabled until the confirmation text matches exactly. Click Delete Account, then confirm the final prompt. This action cannot be undone. All your data will be permanently deleted. After deletion completes, you will be signed out and redirected to the homepage. # Exporting a resume to Markdown Source: https://docs.rxresu.me/guides/exporting-resume-to-markdown Export your Reactive Resume as a portable Markdown file for AI tools, personal websites, notes, version control, or quick plain-text edits. Use Markdown when you want the content of your resume in a portable plain-text format. Markdown keeps headings, lists, links, bold text, and italic text, but it does not try to preserve the visual template, page layout, colors, or spacing from the PDF. Use PDF when you are submitting the finished resume. Use Markdown when you want to reuse, review, transform, or store the resume content. ## Export Markdown Go to the dashboard and open the resume you want to export. Click **Download** in the builder header, or open the **Export** section in the right sidebar and click **Download**. Select **Resume** to export the resume content. Select **Cover letter** if you want a Markdown copy of the cover letter instead. In the **Markdown** row, click **Download**. Your browser saves a `.md` file. Download dialog showing PDF, DOCX, Markdown, and JSON export options for a resume ## Use cases Markdown export is useful when you need readable resume content outside the PDF. | Use case | Why Markdown helps | | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | **AI agents and assistants** | Markdown gives the model structured text with headings and lists, without the layout noise of a PDF. | | **File search and retrieval systems** | `.md` files are easy to index, search, chunk, and cite in retrieval workflows. | | **GitHub profile or portfolio repositories** | GitHub renders Markdown files, so you can reuse resume content in a profile README or portfolio repo. | | **Personal websites and static sites** | Many site generators and CMS workflows accept Markdown as source content. | | **Notes and knowledge bases** | Apps like Obsidian use Markdown syntax, so your resume can live next to job-search notes and interview prep. | | **Version control** | Markdown diffs cleanly, making it easier to review what changed between resume versions. | | **Quick editing** | Open the file in any text editor, make content edits, then copy the text wherever you need it. | ## Example Markdown A shortened export of the built-in sample resume looks like this: ```md theme={null} # David Kowalski _Game Developer | Unity & Unreal Engine Specialist_ david.kowalski@email.com - +1 (555) 291-4756 - Seattle, WA - [davidkowalski.games](https://davidkowalski.games) ## Summary **Passionate game developer with 5+ years of professional experience** creating engaging gameplay systems and polished player experiences across multiple platforms. Specialized in Unity and Unreal Engine with strong expertise in C#, C++, and game design principles. ## Experience ### Cascade Studios - Senior Game Developer (March 2022 - Present) _Seattle, WA_ - Lead gameplay programmer on an unannounced AAA action-adventure title built in Unreal Engine 5 for PC and next-gen consoles - Architected and implemented core combat system including hit detection, combo mechanics, and enemy AI behavior trees serving 15+ enemy types - Developed custom editor tools in C++ that reduced level designer iteration time by 40% and improved workflow efficiency across the team - Optimized rendering pipeline and gameplay systems to maintain 60 FPS performance target on all supported platforms ## Education ### University of Washington - Bachelor of Science, Computer Science (2014 - 2018) _Seattle, WA - Grade: 3.6 GPA_ Concentration in Game Development. Relevant Coursework: Game Engine Architecture, Computer Graphics, Artificial Intelligence, Physics Simulation, 3D Mathematics, Software Engineering, Data Structures & Algorithms ## Skills ### Unity Engine - Expert C# - Editor Tools - Performance Profiling ### Unreal Engine - Advanced C++ - Blueprints - UE5 Features ``` ## What Markdown includes Markdown export includes the visible resume or cover-letter content for the selected tab. It keeps the document structure, section headings, item headings, rich-text paragraphs, lists, links, bold text, and italic text. Markdown export does not include visual-only choices such as template design, page size, column layout, colors, icon styling, spacing, or PDF page breaks. If you are sharing the file with an AI assistant, include the job description in the same prompt and ask for changes as Markdown. That makes the result easy to compare before you update the resume in Reactive Resume. ## When not to use Markdown Do not use Markdown as the final file for most job applications. Applicant portals and recruiters usually expect a PDF or DOCX file. Export Markdown when you need a working copy of the content, then export PDF when you are ready to submit. # Exporting your resume Source: https://docs.rxresu.me/guides/exporting-your-resume Download your resume or cover letter from Reactive Resume as PDF, DOCX, Markdown, or JSON, and pick the right format for each situation. Reactive Resume can export your resume, and your cover letter separately when you have one, in four formats. | Format | Best for | | ------------ | ------------------------------------------------------------------------------------- | | **PDF** | Job applications, recruiter emails, printing, and public resume downloads. | | **DOCX** | Further editing in Microsoft Word, Google Docs, or Pages. | | **Markdown** | Plain-text edits and sharing structured content with AI tools. | | **JSON** | Backups, restoring a resume later, or importing into another Reactive Resume account. | ## Open the download dialog Every export runs from the same **Download** dialog. You can open it two ways. Go to the dashboard and open the resume you want to export. Select the **Download** button in the top-right of the builder header, next to the sidebar toggle. You can also open the same dialog from the **Export** section of the right sidebar. At the top of the dialog, use the tabs to choose **Resume** or **Cover letter**. The **Cover letter** tab is only available when your resume contains a visible cover letter section. Select **Download** on the format you want. The dialog closes and your browser saves the file using the resume name as the filename. While an export is running, the trigger button and format buttons show a spinner and stay disabled until the file is ready. ## Export the resume and cover letter separately If your resume includes a [cover letter section](/guides/adding-a-cover-letter), the download dialog treats the resume and cover letter as two distinct documents. * For PDF, DOCX, and Markdown, the **Resume** tab exports only your resume content and excludes cover letter sections. Its JSON export retains embedded cover-letter custom sections; independent cover letters remain separate dashboard exports. * The **Cover letter** tab exports only visible cover letter sections, rendered full width on their own page. You do not need to reorder pages or hide sections by hand to produce a resume-only or cover-letter-only PDF. Select the tab that matches what you want, then pick a format. The **Cover letter** tab is disabled when the resume has no cover letter section, or when every cover letter section or item is hidden. ## Export as PDF Choose **PDF** when you need a file that preserves your resume layout. Use PDF for: * uploading to job applications; * emailing recruiters or hiring managers; * printing from your browser or a print service; * sharing a finished copy outside Reactive Resume. The PDF is generated from your current resume data, template, typography, design, layout, and page settings. ## Export as DOCX Choose **DOCX** when you want to continue editing your resume or cover letter in a word processor. Use DOCX for: * making final manual edits in Microsoft Word; * collaborating with someone who prefers Word or Google Docs; * submitting to a system that requires a Word document. DOCX exports are useful for editing, but the visual layout may not match the PDF exactly. Use PDF when exact visual fidelity matters. ## Export as Markdown Choose **Markdown** when you want a plain-text version of your resume or cover letter that is easy to edit anywhere and easy to feed into AI tools. Use Markdown for: * pasting into an AI assistant to review, rewrite, or tailor content; * quick edits in any text editor without formatting overhead; * storing a lightweight, diff-friendly copy in version control. Section headings, lists, links, and rich-text formatting from the builder are preserved as standard Markdown. For examples and common workflows, see [Exporting a resume to Markdown](/guides/exporting-resume-to-markdown). ## Export as JSON Choose **JSON** when you want a structured backup of your resume. The JSON export includes your full resume content and settings, including any cover letter sections embedded in that resume. You can import it later from the dashboard to restore the resume or create another version. JSON is also useful when working with AI assistants that understand structured data. Export JSON, ask an assistant to review or edit the fields, then import the revised JSON as a new resume. JSON export in the download dialog is only available on the **Resume** tab. To export an independent letter as JSON, open it from **Cover Letters** on the dashboard and select **Export JSON**. Review AI-generated changes before importing or using them. AI assistants can make mistakes or add details that do not reflect your experience. ## Keep JSON backups in a local Git repository Git can keep owner-controlled versions of your exported resume and cover letter without changing Reactive Resume or connecting it to a Git provider. This workflow is manual and local only: Reactive Resume does not commit, synchronize, or upload the files for you. ### Choose the right exports Reactive Resume provides three different JSON shapes: | Export | How to create it | What it contains | Can you import it as one resume? | | ---------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | | **Single resume** | In the builder, open **Download**, stay on **Resume**, and download **JSON**. | Resume content and settings, including cover letter sections embedded in that resume. | Yes. | | **Independent cover letter** | Open a letter from **Cover Letters** on the dashboard and select **Export JSON**. | That letter's content and copied resume styling in the Reactive Resume cover-letter format. | No. Import it through the cover-letter library instead. | | **Account archive** | Open **Settings**, go to **Account**, and select **Export my data**. | Account profile metadata, all owned resume records, independent cover letters, and an `exportedAt` timestamp. | No. It is an archive, not a single-resume import file. | Use the single-resume and independent-cover-letter exports for the Git workflow below. An account archive is an additional portability backup, not a replacement for those files. Because its `exportedAt` timestamp changes on every export, do not expect otherwise unchanged account archives to be byte-for-byte identical. ### Create the local backup 1. Create a folder outside your Reactive Resume source checkout. 2. Export the resume and each independent cover letter you want to keep. 3. Give the files stable, descriptive names. The example below uses `resume.json` and `cover-letter.json`; replace each file with its latest export instead of changing its name. 4. From that folder, initialize Git and inspect exactly what you are about to commit: ```bash theme={null} git init git add -- resume.json cover-letter.json git diff --cached --stat git diff --cached -- resume.json cover-letter.json git commit -m "Back up resume and cover letter" ``` After the first commit, replace the JSON files with fresh exports and inspect the visible changes before committing again: ```bash theme={null} git diff -- resume.json ``` Stable filenames and the exports' two-space indentation make field changes easier to review. Repeat the add, diff, and commit steps only after the changes look correct. Resume JSON, cover-letter JSON, and especially an account archive can contain private data such as contact details, application text, profile metadata, and email address. A local Git repository does not publish anything. Inspect every diff and decide separately whether to publish it; if you use a remote, make it private and control who can access it. JSON exports store image URLs, not offline copies of image files. An imported backup can show an image only while the referenced storage remains available and accessible. ### Recover an earlier resume without replacing the current one Choose the committed revision of `resume.json` that you want to recover. List commits that changed the file, then inspect the selected revision from the backup folder. Choose a fresh, unused output filename; the example assumes `recovered-resume.json` does not already exist: ```bash theme={null} git log --oneline -- resume.json git show :resume.json git show :resume.json > recovered-resume.json ``` On the Reactive Resume dashboard, select **Import an existing resume**, choose `recovered-resume.json`, and complete the import. Import creates a new resume, so the current resume remains available for comparison or further editing. Only a single-resume JSON export works for this recovery flow. Import independent cover letters through the cover-letter library. Restoring an account archive wholesale is outside this workflow. Git backups complement Reactive Resume's rolling snapshots; they do not replace or synchronize with [undo and version history](/guides/undoing-changes-and-version-history). ## Printing your resume To print, export a **PDF** and print it from your PDF viewer or browser. This gives you the same layout that recruiters see when you send them the file. ## Public resume downloads If your resume is public, visitors can download a PDF from the public resume page. You can enable public access in the builder's **Sharing** section. For the full public sharing workflow, see [Sharing your resume publicly](/guides/sharing-your-resume-publicly). # Fitting content on a page Source: https://docs.rxresu.me/guides/fitting-content-on-a-page Reorganize sections, tune typography, adjust margins, and trim content to fit your Reactive Resume on a single A4 or Letter page without overflow. When your resume content overflows the page, Reactive Resume shows a warning just below the page. This guide covers how to reorganize and trim your content so everything fits your chosen page format. Screenshot of the overflow warning message in the resume builder While Reactive Resume supports multi-page resumes, each page has a fixed height based on your chosen format (A4 or Letter). If a single page's content exceeds this height, parts of your resume may be rendered improperly when printed or exported. ## Quick fixes The fixes below are ordered from simplest to most involved. ### 1. Switch to Free-Form format If you don't plan on printing your resume, switch to **Free-Form** format. Free-Form creates a single continuous page with no height limit, so nothing can overflow. With Free-Form: * Your resume renders as one continuous document * There are no page breaks to manage * ATS parsers and AI scanners can still read your content * You can focus on the content instead of page limits To switch formats, go to the **Page** section in the right sidebar and change the **Format** to Free-Form. For more details, see [Selecting the right page format](/guides/selecting-page-format). Most resumes are read on a screen, so Free-Form is often the best choice unless you need printed copies. ### 2. Shorten text blocks Long paragraphs take up space without adding proportional value. Review each section and cut ruthlessly: * **Use bullet points** instead of paragraphs. Bullets are easier to scan and take less vertical space. * **Remove filler words.** "Was responsible for managing" becomes "Managed." * **Focus on impact.** Keep measurable achievements; cut generic descriptions. * **Limit bullets per entry.** Three to five bullets per job is usually enough. Read each bullet point and ask: "Does this help me get an interview?" If not, cut it. ### 3. Use multi-column layouts Some sections work better in multiple columns, especially lists of short items. In the left sidebar, find the section you want to adjust, click on the section heading (not an item), and change the **Columns** setting. Screenshot of the columns setting for a section Good candidates for multi-column layouts: | Section | Recommended Columns | | ------------------------- | ------------------- | | Skills | > 2 columns | | Languages | > 3 columns | | Interests | > 2 columns | | Profiles | > 3 columns | | Certifications (if brief) | > 2 columns | Multi-column layouts work best for sections with short, uniform items. Sections with long descriptions (like Experience or Projects) usually work better in a single column. ### 4. Move items to another page If you have more content than fits on one page, move less important items to page two. This keeps your first page focused on your most relevant experience. Use the **Move to** feature to relocate items: 1. Open the item's dropdown menu (three-dot icon) 2. Hover over **Move to** 3. Select the destination page For detailed instructions, see [Moving items between sections](/guides/moving-items-between-sections). Keep your most recent and relevant experience on page one. Move older positions or less critical sections (like older projects or volunteer work) to subsequent pages. ### 5. Adjust layout and design settings The right sidebar contains settings that control how much space your content uses. Small adjustments here can make a big difference. Open the right sidebar and explore these options: | Setting | Where to find it | Effect | | ----------------- | ---------------------- | ------------------------------------------------------ | | **Font size** | Typography | Smaller fonts fit more text per line and per page | | **Line height** | Typography | Tighter line spacing reduces vertical space | | **Margins** | Page | Smaller margins give you more usable area | | **Section gaps** | Page | Reducing gaps between sections saves space | | **Sidebar width** | Layout | Adjusting the sidebar ratio can balance content better | | **Picture size** | Picture (left sidebar) | A smaller photo leaves more room for text | **Reducing font size is the best option** when you need to fit more content while keeping A4 or Letter format. Reducing body font from 11pt to 10.5pt (or even 10pt) can free up significant space while remaining readable. The editor supports 0.1pt increments, so you can fine-tune precisely. ### 6. Hide less important sections If you're still short on space, consider hiding sections that aren't essential for your target role: * **Interests**: nice to have, but rarely a deciding factor * **References**: "Available upon request" is assumed, so you don't need to list them * **Older certifications**: keep only the ones relevant to the job * **Volunteer work**: include only if it strengthens your application To hide a section, click on the section heading in the left sidebar and toggle the **Hidden** switch. ## Finding the right balance If you need to stick with A4 or Letter format, start with content changes (steps 2-4) before adjusting design settings (steps 5-6). A resume that fits its content reads better than one crammed into the space. Try this order: 1. Consider switching to Free-Form if printing isn't required 2. Cut unnecessary text first 3. Reorganize with columns where appropriate 4. Move secondary content to page two if needed 5. Fine-tune font size and spacing last Use the live preview to see changes as you make them. Small adjustments add up. Reducing font size by 0.5pt along with slightly smaller margins can recover enough space for several lines of content. ## Troubleshooting ### Content still overflows after trying everything If you've tried all the above and content still overflows: * **Re-evaluate what's essential.** Every item should earn its place. Cut aggressively. * **Try a different template.** Some templates are more space-efficient than others. ### The preview looks different from the PDF The PDF export matches the preview exactly. If they appear different, try: * Refreshing the page * Checking that all fonts have loaded * Ensuring your browser zoom is at 100% ### I made the font too small and now it's hard to read Resume fonts should stay between 9pt and 12pt for body text. If you've gone below 9pt to fit content, you're trying to include too much. Go back to step 1 and cut more content instead. # Importing applications from CSV Source: https://docs.rxresu.me/guides/importing-applications-from-csv Move existing job applications into the Reactive Resume Application Tracker by uploading a CSV file or pasting spreadsheet rows with headers. Use CSV import when you already track applications in a spreadsheet and want to move them into Reactive Resume. ## Open CSV import In the dashboard sidebar, click **Applications**. If you have no applications yet, click **Import from CSV** in the empty state. Otherwise, click **Import CSV** in the page header. CSV import sheet showing upload, pasted CSV rows, recognized fields, and one application ready to import ## Prepare your CSV The importer uses the first row as headers. Each imported row must include a company and role. Supported headers include: | Field | Recognized headers | | ------------------- | ---------------------------------------- | | **Company** | `Company`, `Employer`, `Organization` | | **Role** | `Role`, `Title`, `Position`, `Job Title` | | **Stage** | `Stage`, `Status` | | **Location** | `Location` | | **Salary** | `Salary`, `Salary Range`, `Compensation` | | **Source** | `Source` | | **Notes** | `Notes`, `Note` | | **Job posting URL** | `URL`, `Link`, `Job URL`, `Job Posting` | | **Tags** | `Tags` | | **Contact name** | `Contact Name` | | **Contact role** | `Contact Role` | | **Contact label** | `Contact Type` | | **Contact email** | `Contact Email` | | **Contact phone** | `Contact Phone` | Tags can be separated with commas, semicolons, or vertical bars. Each row can carry one contact. A contact needs a `Contact Name`, and `Contact Email` must be a valid email address — if either is wrong, the contact is dropped and the application still imports. ```csv theme={null} Company,Role,Stage,Location,Salary,Source,Tags,Contact Name,Contact Email,Contact Phone Stripe,Frontend Engineer,applied,Remote,$180k,LinkedIn,remote;react,Jane Doe,jane@example.com,+1 555 0100 ``` ## Import applications Upload a `.csv` file, or paste CSV rows directly into the **CSV data** field. Reactive Resume shows how many rows are ready to import, which columns it recognized, and how many rows were skipped. Rows without a company or role are skipped. Add the missing values before importing if you want those rows included. The preview also counts skipped contacts — those rows still import, just without the contact. Click **Import**. Imported applications are added to your Application Tracker. ## Use valid stages The **Stage** column is optional. If you include it, use one of these values: * `saved` * `applied` * `screening` * `interview` * `offer` * `rejected` If a row has an unrecognized stage, the importer ignores that stage value and uses the default application stage. ## Import large files Reactive Resume imports up to 500 applications at a time. If your CSV has more than 500 valid rows, split it into smaller files and import each file separately. Import first, then use the table view to select multiple applications and apply tags, move stages, archive rows, or delete rows in bulk. MCP clients can also import application rows directly with `import_applications`. See [Managing applications with MCP](/guides/managing-applications-with-mcp) for agent prompt examples. ## Troubleshooting ### Some rows were skipped Make sure every row has both a company and a role. These fields are required. ### A contact did not import The contact needs a `Contact Name`, and `Contact Email` must be a valid address. The application imports either way — fix the contact columns and import that row again if you want the contact. ### A column was not recognized Rename the header to one of the recognized names in the table above, then import again. ### Tags did not split correctly Separate tags with commas, semicolons, or vertical bars, such as `remote;react` or `frontend|senior`. ### A stage did not import Use lowercase stage values such as `applied` or `interview`. Custom stages are not supported. # Importing resumes Source: https://docs.rxresu.me/guides/importing-resumes Import a resume from JSON, JSON Resume, PDF, or Microsoft Word files with automatic format detection from the Reactive Resume dashboard. Reactive Resume can create a new resume from several existing file formats. Use import when you are moving from another tool, restoring a backup, or converting an older Reactive Resume file. ## Supported import formats | Format | Requires AI integration? | Notes | | ----------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------ | | **Reactive Resume (JSON)** | No | Best option for backups exported from the current version of Reactive Resume. | | **Reactive Resume v4 (JSON)** | No | Use this for files exported from Reactive Resume v4. | | **JSON Resume** | No | Use this for files that follow the JSON Resume schema. | | **PDF** | Yes | Reactive Resume asks your configured AI provider to parse the file into structured resume data. | | **Microsoft Word** | Yes | Supports Word documents. Reactive Resume asks your configured AI provider to parse the document. | PDF and Word imports depend on your AI settings because those formats are not structured resume data. Configure AI in **Dashboard → Settings → Integrations** before using those import types. ## Import a resume Sign in and go to **Dashboard → Resumes**. Click the **Import** card (or the header button if you already have resumes). Import dialog showing the file picker and detected import format Select the resume file from your computer. Reactive Resume detects the format automatically from the file's contents and shows the matching import type. If auto-detection is uncertain, or you want to force a specific format, adjust the import type manually before continuing. Click **Import**. Reactive Resume creates a new resume and opens it in the builder when the import succeeds. For PDF and Microsoft Word files, the dialog checks that you have a working AI provider configured before it starts. If none is available, you'll get a link to **Integrations** to set one up. ## Choose the right import type If you have a file exported from Reactive Resume, choose **Reactive Resume (JSON)**. This preserves the most information because the file already matches Reactive Resume's data model. If you are coming from Reactive Resume v4, choose **Reactive Resume v4 (JSON)**. If your file is a standard JSON Resume document, choose **JSON Resume**. If you only have a PDF or Word document, choose **PDF** or **Microsoft Word**. After import, review every section carefully. AI parsing can save time, but it can also miss details, change wording, or place content in the wrong section. Always review an imported resume before sharing or exporting it. This is especially important for PDF and Word imports. ## Troubleshooting ### The PDF or Word import says AI must be enabled Open **Dashboard → Settings → Integrations**, fill in your AI provider settings, test the connection, and enable AI features. ### The imported resume is incomplete Try importing a cleaner source file. Simple resumes with selectable text import more reliably than scanned documents, image-heavy PDFs, or files with complex tables. ### The JSON file is rejected Make sure you selected the correct JSON import type. A Reactive Resume JSON export, a Reactive Resume v4 JSON export, and a JSON Resume file are different formats. # JSON Resume Schema Source: https://docs.rxresu.me/guides/json-resume-schema Learn about the Reactive Resume JSON Schema, available at /schema.json, and how it aims to become the gold standard for portable resume data. ## The Vision I envision a world where applying for a job is as simple as transferring a JSON file from one service to a job listing portal—without any parsing errors, format inconsistencies, or human bias from subjective resume formatting. Reactive Resume aims to be the **gold standard in JSON Resume Schemas**. A universal, well-documented, and rigorously typed schema that any service can adopt to enable seamless resume portability across the entire job application ecosystem. Imagine: * Exporting your resume from Reactive Resume as a JSON file * Uploading it directly to a job portal that instantly understands every field * No more PDF parsing failures or ATS (Applicant Tracking System) misreads * Your qualifications evaluated purely on merit, not on formatting quirks This is the future I'm hoping to build toward. ## The Schema Endpoint The Reactive Resume JSON Schema is publicly available at: [https://rxresu.me/schema.json](https://rxresu.me/schema.json) This endpoint returns a complete JSON Schema (draft 07 compatible) that describes the structure of a Reactive Resume document. It includes: * **All resume sections**: basics, summary, experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer work, and references * **Custom sections**: user-defined sections with arbitrary content * **Metadata**: template, layout, typography, colors, page settings, and custom CSS * **Full descriptions**: every field is documented with its purpose and expected format ## Schema Versioning The schema includes a `version` field to track compatibility: ```json theme={null} { "$schema": "https://rxresu.me/schema.json", "version": "5.0.0" } ``` When importing resumes, Reactive Resume uses this version to handle migrations and ensure backward compatibility. ## Using the Schema ### Validating Resume Data You can use the schema to validate resume JSON files in any language that supports JSON Schema validation: ```javascript theme={null} import Ajv from "ajv"; const ajv = new Ajv(); const schema = await fetch("https://rxresu.me/schema.json").then((r) => r.json()); const validate = ajv.compile(schema); const isValid = validate(resumeData); if (!isValid) { console.error(validate.errors); } ``` ### IDE Autocompletion Add the `$schema` property to your resume JSON files to get autocompletion and validation in editors like VS Code: ```json theme={null} { "$schema": "https://rxresu.me/schema.json", "version": "5.0.0", "basics": { "name": "John Doe" } } ``` ### Building Integrations The schema enables third-party integrations: * **Job portals** can accept Reactive Resume JSON files directly * **HR systems** can parse candidate data without lossy PDF conversion * **Other resume builders** can import/export using a common format * **AI tools** can understand resume structure for analysis or enhancement ## Schema Structure Overview The resume data is organized into these top-level sections: | Section | Description | | ---------------- | ----------------------------------------------- | | `$schema` | URL to the JSON Schema for validation | | `version` | Schema version (currently `5.0.0`) | | `picture` | Profile photo configuration | | `basics` | Name, headline, contact info, custom fields | | `summary` | Professional summary or bio | | `sections` | Standard sections (experience, education, etc.) | | `customSections` | User-defined additional sections | | `metadata` | Template, layout, design, typography settings | Each section within `sections` follows a consistent structure: ```json theme={null} { "title": "Experience", "columns": 1, "hidden": false, "items": [ { "id": "uuid", "hidden": false // ... section-specific fields } ] } ``` ## For Developers & Job Portals If you're building a job portal, HR system, or any service that handles resumes, I encourage you to adopt this schema. Benefits include: * **Zero parsing errors**: structured data means no OCR or PDF parsing mistakes * **Complete information**: all resume data is preserved, including links and metadata * **Easy integration**: JSON is universally supported across all platforms * **Future-proof**: versioned schema with migration support Want to integrate? The schema is open and freely available. You can fetch it programmatically or reference it in your systems. ## Complete JSON Schema Below is the complete JSON Schema for Reactive Resume. You can also fetch the latest version directly from [https://rxresu.me/schema.json](https://rxresu.me/schema.json). Copy the schema from the live endpoint to ensure you always have the latest version. ```json /schema.json lines expandable theme={null} { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "properties": { "picture": { "type": "object", "properties": { "hidden": { "type": "boolean", "description": "Whether to hide the picture from the resume." }, "url": { "type": "string", "description": "The URL to the picture to display on the resume. Prefer local app-served paths (for example /uploads/...) populated via upload." }, "size": { "type": "number", "minimum": 32, "maximum": 512, "description": "The size of the picture to display on the resume, defined in points (pt)." }, "rotation": { "type": "number", "minimum": 0, "maximum": 360, "description": "The rotation of the picture to display on the resume, defined in degrees (°)." }, "aspectRatio": { "type": "number", "minimum": 0.5, "maximum": 2.5, "description": "The aspect ratio of the picture to display on the resume, defined as width / height (e.g. 1.5 for 1.5:1 or 0.5 for 1:2)." }, "borderRadius": { "type": "number", "minimum": 0, "maximum": 100, "description": "The border radius of the picture to display on the resume, defined in points (pt)." }, "borderColor": { "type": "string", "description": "The color of the border of the picture to display on the resume, defined as rgba(r, g, b, a)." }, "borderWidth": { "type": "number", "minimum": 0, "description": "The width of the border of the picture to display on the resume, defined in points (pt)." }, "shadowColor": { "type": "string", "description": "The color of the shadow of the picture to display on the resume, defined as rgba(r, g, b, a)." }, "shadowWidth": { "type": "number", "minimum": 0, "description": "The width of the shadow of the picture to display on the resume, defined in points (pt)." } }, "required": [ "hidden", "url", "size", "rotation", "aspectRatio", "borderRadius", "borderColor", "borderWidth", "shadowColor", "shadowWidth" ], "additionalProperties": false, "description": "Configuration for photograph displayed on the resume" }, "basics": { "type": "object", "properties": { "name": { "type": "string", "description": "The full name of the author of the resume." }, "headline": { "type": "string", "description": "The headline of the author of the resume." }, "email": { "type": "string", "description": "The email address of the author of the resume." }, "phone": { "type": "string", "description": "The phone number of the author of the resume." }, "location": { "type": "string", "description": "The location of the author of the resume." }, "website": { "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." } }, "required": ["url", "label"], "additionalProperties": false, "description": "The website of the author of the resume." }, "customFields": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the custom field. Usually generated as a UUID." }, "icon": { "type": "string", "description": "The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available." }, "text": { "type": "string", "description": "The text to display for the custom field." }, "link": { "default": "", "type": "string", "description": "If the custom field should be a link, the URL to link to." } }, "required": ["id", "icon", "text", "link"], "additionalProperties": false }, "description": "The custom fields to display on the resume." } }, "required": ["name", "headline", "email", "phone", "location", "website", "customFields"], "additionalProperties": false, "description": "Basic information about the author, such as name, email, phone, location, and website" }, "summary": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the summary of the resume." }, "columns": { "default": 1, "description": "The number of columns the summary should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the summary from the resume." }, "content": { "type": "string", "description": "The content of the summary of the resume. This should be a HTML-formatted string." } }, "required": ["title", "columns", "hidden", "content"], "additionalProperties": false, "description": "Summary section of the resume, useful for a short bio or introduction" }, "sections": { "type": "object", "properties": { "profiles": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "icon": { "type": "string", "description": "The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available." }, "iconColor": { "default": "", "description": "Custom color for the icon, defined as rgba(r, g, b, a). Leave blank to use the template default icon color.", "type": "string" }, "network": { "type": "string", "minLength": 1, "description": "The name of the network or platform." }, "username": { "type": "string", "description": "The username of the author on the network or platform." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The link to the profile of the author on the network or platform, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false } }, "required": ["id", "hidden", "icon", "iconColor", "network", "username", "website"], "additionalProperties": false }, "description": "The items to display in the profiles section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the profiles of the author." }, "experience": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "company": { "type": "string", "minLength": 1, "description": "The name of the company or organization." }, "position": { "type": "string", "description": "The position held at the company or organization. Used when there is only a single role. If multiple roles are provided in the 'roles' field, this serves as a summary title or can be left blank." }, "location": { "type": "string", "description": "The location of the company or organization." }, "period": { "type": "string", "description": "The overall period of time at the company. When multiple roles are used, this should reflect the total tenure." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website of the company or organization, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the experience. This should be a HTML-formatted string." }, "roles": { "default": [], "description": "List of individual roles held at this company to show career progression.", "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the role. Usually generated as a UUID." }, "position": { "type": "string", "description": "The position or job title for this role." }, "period": { "type": "string", "description": "The period of time this role was held." }, "description": { "type": "string", "description": "The description of this specific role. This should be a HTML-formatted string." } }, "required": ["id", "position", "period", "description"], "additionalProperties": false } } }, "required": [ "id", "hidden", "company", "position", "location", "period", "website", "description", "roles" ], "additionalProperties": false }, "description": "The items to display in the experience section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the experience of the author." }, "education": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "school": { "type": "string", "minLength": 1, "description": "The name of the school or institution." }, "degree": { "type": "string", "description": "The degree or qualification obtained." }, "area": { "type": "string", "description": "The area of study or specialization." }, "grade": { "type": "string", "description": "The grade or score achieved." }, "location": { "type": "string", "description": "The location of the school or institution." }, "period": { "type": "string", "description": "The period of time the education was obtained over." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website of the school or institution, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the education. This should be a HTML-formatted string." } }, "required": [ "id", "hidden", "school", "degree", "area", "grade", "location", "period", "website", "description" ], "additionalProperties": false }, "description": "The items to display in the education section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the education of the author." }, "projects": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "name": { "type": "string", "minLength": 1, "description": "The name of the project." }, "period": { "type": "string", "description": "The period of time the project was worked on." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The link to the project, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the project. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "name", "period", "website", "description"], "additionalProperties": false }, "description": "The items to display in the projects section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the projects of the author." }, "skills": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "icon": { "type": "string", "description": "The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available." }, "iconColor": { "default": "", "description": "Custom color for the icon, defined as rgba(r, g, b, a). Leave blank to use the template default icon color.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "The name of the skill." }, "proficiency": { "type": "string", "description": "The proficiency level of the skill. Can be any text, such as 'Beginner', 'Intermediate', 'Advanced', etc." }, "level": { "default": 0, "description": "The proficiency level of the skill, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden.", "type": "number", "minimum": 0, "maximum": 5 }, "keywords": { "default": [], "description": "The keywords associated with the skill, if any. These are displayed as tags below the name.", "type": "array", "items": { "type": "string" } } }, "required": ["id", "hidden", "icon", "iconColor", "name", "proficiency", "level", "keywords"], "additionalProperties": false }, "description": "The items to display in the skills section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the skills of the author." }, "languages": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "language": { "type": "string", "minLength": 1, "description": "The name of the language the author knows." }, "fluency": { "type": "string", "description": "The fluency level of the language. Can be any text, such as 'Native', 'Fluent', 'Conversational', etc. or can also be a CEFR level (A1, A2, B1, B2, C1, C2)." }, "level": { "default": 0, "description": "The proficiency level of the language, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden.", "type": "number", "minimum": 0, "maximum": 5 } }, "required": ["id", "hidden", "language", "fluency", "level"], "additionalProperties": false }, "description": "The items to display in the languages section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the languages of the author." }, "interests": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "icon": { "type": "string", "description": "The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available." }, "iconColor": { "default": "", "description": "Custom color for the icon, defined as rgba(r, g, b, a). Leave blank to use the template default icon color.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "The name of the interest/hobby." }, "keywords": { "default": [], "description": "The keywords associated with the interest/hobby, if any. These are displayed as tags below the name.", "type": "array", "items": { "type": "string" } } }, "required": ["id", "hidden", "icon", "iconColor", "name", "keywords"], "additionalProperties": false }, "description": "The items to display in the interests section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the interests of the author." }, "awards": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "title": { "type": "string", "minLength": 1, "description": "The title of the award." }, "awarder": { "type": "string", "description": "The awarder of the award." }, "date": { "type": "string", "description": "The date when the award was received." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website of the award, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the award. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "title", "awarder", "date", "website", "description"], "additionalProperties": false }, "description": "The items to display in the awards section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the awards of the author." }, "certifications": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "title": { "type": "string", "minLength": 1, "description": "The title of the certification." }, "issuer": { "type": "string", "description": "The issuer of the certification." }, "date": { "type": "string", "description": "The date when the certification was received." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website of the certification, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the certification. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "title", "issuer", "date", "website", "description"], "additionalProperties": false }, "description": "The items to display in the certifications section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the certifications of the author." }, "publications": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "title": { "type": "string", "minLength": 1, "description": "The title of the publication." }, "publisher": { "type": "string", "description": "The publisher of the publication." }, "date": { "type": "string", "description": "The date when the publication was published." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The link to the publication, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the publication. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "title", "publisher", "date", "website", "description"], "additionalProperties": false }, "description": "The items to display in the publications section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the publications of the author." }, "volunteer": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "organization": { "type": "string", "minLength": 1, "description": "The name of the organization or company." }, "location": { "type": "string", "description": "The location of the organization or company." }, "period": { "type": "string", "description": "The period of time the author was volunteered at the organization or company." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The link to the organization or company, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the volunteer experience. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "organization", "location", "period", "website", "description"], "additionalProperties": false }, "description": "The items to display in the volunteer section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the volunteer experience of the author." }, "references": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "items": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "name": { "type": "string", "minLength": 1, "description": "The name of the reference, or a note such as 'Available upon request'." }, "position": { "type": "string", "description": "The position or job title of the reference." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website or LinkedIn profile of the reference, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "phone": { "type": "string", "description": "The phone number of the reference." }, "description": { "type": "string", "description": "The description of the reference. Can be used to display a quote, a testimonial, etc. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "name", "position", "website", "phone", "description"], "additionalProperties": false }, "description": "The items to display in the references section." } }, "required": ["title", "columns", "hidden", "items"], "additionalProperties": false, "description": "The section to display the references of the author." } }, "required": [ "profiles", "experience", "education", "projects", "skills", "languages", "interests", "awards", "certifications", "publications", "volunteer", "references" ], "additionalProperties": false, "description": "Various sections of the resume, such as experience, education, projects, etc." }, "customSections": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string", "description": "The title of the section." }, "columns": { "default": 1, "description": "The number of columns the section should span across.", "type": "integer", "minimum": 1, "maximum": 6 }, "hidden": { "type": "boolean", "description": "Whether to hide the section from the resume." }, "id": { "type": "string", "description": "The unique identifier for the custom section. Usually generated as a UUID." }, "type": { "type": "string", "enum": [ "summary", "profiles", "experience", "education", "projects", "skills", "languages", "interests", "awards", "certifications", "publications", "volunteer", "references", "cover-letter" ], "description": "The type of items this custom section contains. Determines which item schema and form fields to use." }, "items": { "type": "array", "items": { "anyOf": [ { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "recipient": { "type": "string", "description": "The recipient's address block as HTML (name, title, company, address, email)." }, "content": { "type": "string", "description": "The cover letter body as HTML (salutation, paragraphs, closing, signature)." } }, "required": ["id", "hidden", "recipient", "content"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "content": { "type": "string", "description": "The rich text content of the summary item. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "content"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "icon": { "type": "string", "description": "The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available." }, "iconColor": { "default": "", "description": "Custom color for the icon, defined as rgba(r, g, b, a). Leave blank to use the template default icon color.", "type": "string" }, "network": { "type": "string", "minLength": 1, "description": "The name of the network or platform." }, "username": { "type": "string", "description": "The username of the author on the network or platform." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The link to the profile of the author on the network or platform, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false } }, "required": ["id", "hidden", "icon", "iconColor", "network", "username", "website"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "company": { "type": "string", "minLength": 1, "description": "The name of the company or organization." }, "position": { "type": "string", "description": "The position held at the company or organization. Used when there is only a single role. If multiple roles are provided in the 'roles' field, this serves as a summary title or can be left blank." }, "location": { "type": "string", "description": "The location of the company or organization." }, "period": { "type": "string", "description": "The overall period of time at the company. When multiple roles are used, this should reflect the total tenure." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website of the company or organization, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the experience. This should be a HTML-formatted string." }, "roles": { "default": [], "description": "List of individual roles held at this company to show career progression.", "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the role. Usually generated as a UUID." }, "position": { "type": "string", "description": "The position or job title for this role." }, "period": { "type": "string", "description": "The period of time this role was held." }, "description": { "type": "string", "description": "The description of this specific role. This should be a HTML-formatted string." } }, "required": ["id", "position", "period", "description"], "additionalProperties": false } } }, "required": [ "id", "hidden", "company", "position", "location", "period", "website", "description", "roles" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "school": { "type": "string", "minLength": 1, "description": "The name of the school or institution." }, "degree": { "type": "string", "description": "The degree or qualification obtained." }, "area": { "type": "string", "description": "The area of study or specialization." }, "grade": { "type": "string", "description": "The grade or score achieved." }, "location": { "type": "string", "description": "The location of the school or institution." }, "period": { "type": "string", "description": "The period of time the education was obtained over." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website of the school or institution, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the education. This should be a HTML-formatted string." } }, "required": [ "id", "hidden", "school", "degree", "area", "grade", "location", "period", "website", "description" ], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "name": { "type": "string", "minLength": 1, "description": "The name of the project." }, "period": { "type": "string", "description": "The period of time the project was worked on." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The link to the project, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the project. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "name", "period", "website", "description"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "icon": { "type": "string", "description": "The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available." }, "iconColor": { "default": "", "description": "Custom color for the icon, defined as rgba(r, g, b, a). Leave blank to use the template default icon color.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "The name of the skill." }, "proficiency": { "type": "string", "description": "The proficiency level of the skill. Can be any text, such as 'Beginner', 'Intermediate', 'Advanced', etc." }, "level": { "default": 0, "description": "The proficiency level of the skill, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden.", "type": "number", "minimum": 0, "maximum": 5 }, "keywords": { "default": [], "description": "The keywords associated with the skill, if any. These are displayed as tags below the name.", "type": "array", "items": { "type": "string" } } }, "required": ["id", "hidden", "icon", "iconColor", "name", "proficiency", "level", "keywords"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "language": { "type": "string", "minLength": 1, "description": "The name of the language the author knows." }, "fluency": { "type": "string", "description": "The fluency level of the language. Can be any text, such as 'Native', 'Fluent', 'Conversational', etc. or can also be a CEFR level (A1, A2, B1, B2, C1, C2)." }, "level": { "default": 0, "description": "The proficiency level of the language, defined as a number between 0 and 5. If set to 0, the icons displaying the level will be hidden.", "type": "number", "minimum": 0, "maximum": 5 } }, "required": ["id", "hidden", "language", "fluency", "level"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "icon": { "type": "string", "description": "The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available." }, "iconColor": { "default": "", "description": "Custom color for the icon, defined as rgba(r, g, b, a). Leave blank to use the template default icon color.", "type": "string" }, "name": { "type": "string", "minLength": 1, "description": "The name of the interest/hobby." }, "keywords": { "default": [], "description": "The keywords associated with the interest/hobby, if any. These are displayed as tags below the name.", "type": "array", "items": { "type": "string" } } }, "required": ["id", "hidden", "icon", "iconColor", "name", "keywords"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "title": { "type": "string", "minLength": 1, "description": "The title of the award." }, "awarder": { "type": "string", "description": "The awarder of the award." }, "date": { "type": "string", "description": "The date when the award was received." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website of the award, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the award. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "title", "awarder", "date", "website", "description"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "title": { "type": "string", "minLength": 1, "description": "The title of the certification." }, "issuer": { "type": "string", "description": "The issuer of the certification." }, "date": { "type": "string", "description": "The date when the certification was received." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website of the certification, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the certification. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "title", "issuer", "date", "website", "description"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "title": { "type": "string", "minLength": 1, "description": "The title of the publication." }, "publisher": { "type": "string", "description": "The publisher of the publication." }, "date": { "type": "string", "description": "The date when the publication was published." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The link to the publication, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the publication. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "title", "publisher", "date", "website", "description"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "organization": { "type": "string", "minLength": 1, "description": "The name of the organization or company." }, "location": { "type": "string", "description": "The location of the organization or company." }, "period": { "type": "string", "description": "The period of time the author was volunteered at the organization or company." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The link to the organization or company, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "description": { "type": "string", "description": "The description of the volunteer experience. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "organization", "location", "period", "website", "description"], "additionalProperties": false }, { "type": "object", "properties": { "id": { "type": "string", "description": "The unique identifier for the item. Usually generated as a UUID." }, "hidden": { "type": "boolean", "description": "Whether to hide the item from the resume." }, "name": { "type": "string", "minLength": 1, "description": "The name of the reference, or a note such as 'Available upon request'." }, "position": { "type": "string", "description": "The position or job title of the reference." }, "website": { "default": { "url": "", "label": "", "inlineLink": false }, "description": "The website or LinkedIn profile of the reference, if any.", "type": "object", "properties": { "url": { "type": "string", "description": "The URL to show as a link. Must be a valid URL with a protocol (http:// or https://)." }, "label": { "type": "string", "description": "The label to display for the URL. Leave blank to display the URL as-is." }, "inlineLink": { "default": false, "description": "If true, the website URL is rendered as a hyperlink on the title instead of a separate link at the bottom.", "type": "boolean" } }, "required": ["url", "label", "inlineLink"], "additionalProperties": false }, "phone": { "type": "string", "description": "The phone number of the reference." }, "description": { "type": "string", "description": "The description of the reference. Can be used to display a quote, a testimonial, etc. This should be a HTML-formatted string." } }, "required": ["id", "hidden", "name", "position", "website", "phone", "description"], "additionalProperties": false } ] }, "description": "The items to display in the custom section. Items follow the schema of the section type." } }, "required": ["title", "columns", "hidden", "id", "type", "items"], "additionalProperties": false }, "description": "Custom sections of the resume, such as a custom section for notes, etc." }, "metadata": { "type": "object", "properties": { "template": { "default": "onyx", "description": "The template to use for the resume. Determines the overall design and appearance of the resume.", "type": "string", "enum": [ "azurill", "bronzor", "chikorita", "ditgar", "ditto", "gengar", "glalie", "kakuna", "lapras", "leafish", "meowth", "onyx", "pikachu", "rhyhorn", "scizor" ] }, "layout": { "type": "object", "properties": { "sidebarWidth": { "default": 35, "description": "The width of the sidebar column, defined as a percentage of the page width.", "type": "number", "minimum": 10, "maximum": 50 }, "pages": { "type": "array", "items": { "type": "object", "properties": { "fullWidth": { "type": "boolean", "description": "Whether the layout of the page should be full width. If true, the main column will span the entire width of the page. This means that there should be no items in the sidebar column." }, "main": { "type": "array", "items": { "type": "string" }, "description": "The items to display in the main column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)." }, "sidebar": { "type": "array", "items": { "type": "string" }, "description": "The items to display in the sidebar column of the page. A string array of section IDs (experience, education, projects, skills, languages, interests, awards, certifications, publications, volunteer, references, profiles, summary or UUIDs for custom sections)." } }, "required": ["fullWidth", "main", "sidebar"], "additionalProperties": false }, "description": "The pages to display in the layout." } }, "required": ["sidebarWidth", "pages"], "additionalProperties": false, "description": "The layout of the resume. Determines the structure and arrangement of the sections on the resume." }, "page": { "type": "object", "properties": { "gapX": { "type": "number", "minimum": 0, "description": "The horizontal gap between the sections of the page, defined in points (pt)." }, "gapY": { "type": "number", "minimum": 0, "description": "The vertical gap between the sections of the page, defined in points (pt)." }, "marginX": { "type": "number", "minimum": 0, "description": "The horizontal margin of the page, defined in points (pt)." }, "marginY": { "type": "number", "minimum": 0, "description": "The vertical margin of the page, defined in points (pt)." }, "format": { "default": "a4", "type": "string", "enum": ["a4", "letter"], "description": "The format of the page. Can be 'a4' or 'letter'." }, "locale": { "default": "en-US", "type": "string", "description": "The locale of the page. Used for displaying pre-translated section headings, if not overridden." }, "hideIcons": { "default": false, "type": "boolean", "description": "Whether to hide the icons of the sections." } }, "required": ["gapX", "gapY", "marginX", "marginY", "format", "locale", "hideIcons"], "additionalProperties": false, "description": "The page settings of the resume. Determines the margins, format, and locale of the resume." }, "design": { "type": "object", "properties": { "level": { "type": "object", "properties": { "icon": { "type": "string", "description": "The icon to display for the custom field. Must be a valid icon name from @phosphor-icons/web icon set, or an empty string to hide. Default to '' (empty string) when unsure which icons are available." }, "type": { "type": "string", "enum": ["hidden", "circle", "square", "rectangle", "rectangle-full", "progress-bar", "icon"], "description": "The type of the level design. 'hidden' will hide the level design, 'circle' will display a circle, 'square' will display a square, 'rectangle' will display a rectangle, 'rectangle-full' will display a full rectangle, 'progress-bar' will display a progress bar, and 'icon' will display an icon. If 'icon' is selected, the icon to display should be specified in the 'icon' field." } }, "required": ["icon", "type"], "additionalProperties": false }, "colors": { "type": "object", "properties": { "primary": { "type": "string", "description": "The primary color of the design, defined as rgba(r, g, b, a)." }, "text": { "type": "string", "description": "The text color of the design, defined as rgba(r, g, b, a). Usually set to black: rgba(0, 0, 0, 1)." }, "background": { "type": "string", "description": "The background color of the design, defined as rgba(r, g, b, a). Usually set to white: rgba(255, 255, 255, 1)." } }, "required": ["primary", "text", "background"], "additionalProperties": false } }, "required": ["level", "colors"], "additionalProperties": false, "description": "The design settings of the resume. Determines the colors, level designs, and typography of the resume." }, "typography": { "type": "object", "properties": { "body": { "type": "object", "properties": { "fontFamily": { "type": "string", "description": "The family of the font to use. Must be a supported resume font." }, "fontWeights": { "default": ["400"], "description": "The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font.", "type": "array", "items": { "type": "string", "enum": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] } }, "fontSize": { "default": 11, "description": "The size of the font to use, defined in points (pt).", "type": "number", "minimum": 6, "maximum": 24 }, "lineHeight": { "default": 1.5, "description": "The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x).", "type": "number", "minimum": 0.5, "maximum": 4 } }, "required": ["fontFamily", "fontWeights", "fontSize", "lineHeight"], "additionalProperties": false, "description": "The typography for the body of the resume." }, "heading": { "type": "object", "properties": { "fontFamily": { "type": "string", "description": "The family of the font to use. Must be a supported resume font." }, "fontWeights": { "default": ["400"], "description": "The weight of the font, defined as a number between 100 and 900. Default to 400 when unsure if the weight is available in the font.", "type": "array", "items": { "type": "string", "enum": ["100", "200", "300", "400", "500", "600", "700", "800", "900"] } }, "fontSize": { "default": 11, "description": "The size of the font to use, defined in points (pt).", "type": "number", "minimum": 6, "maximum": 24 }, "lineHeight": { "default": 1.5, "description": "The line height of the font to use, defined as a multiplier of the font size (e.g. 1.5 for 1.5x).", "type": "number", "minimum": 0.5, "maximum": 4 } }, "required": ["fontFamily", "fontWeights", "fontSize", "lineHeight"], "additionalProperties": false, "description": "The typography for the headings of the resume." } }, "required": ["body", "heading"], "additionalProperties": false, "description": "The typography settings of the resume. Determines the fonts and sizes of the body and headings of the resume." }, "notes": { "type": "string", "description": "Personal notes for the resume. Can be used to add any additional information or instructions for the resume. These notes are not displayed on the resume, they are only visible to the author of the resume when editing the resume. This should be a HTML-formatted string." } }, "required": ["template", "layout", "page", "design", "typography", "notes"], "additionalProperties": false, "description": "Metadata for the resume, such as template, layout, typography, etc. This section describes the overall design and appearance of the resume." } }, "required": ["picture", "basics", "summary", "sections", "customSections", "metadata"], "additionalProperties": false } ``` # Linking social accounts Source: https://docs.rxresu.me/guides/linking-social-accounts Connect or disconnect social sign-in providers like Google and GitHub to your Reactive Resume account so you can sign in without a password. Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials. In the dashboard sidebar on the left, under Settings, click the Authentication link. On the Authentication page, you may see sections for one or more providers (for example, Google or GitHub), depending on what is enabled on your instance. Click the Connect button for the provider you want to link. You'll be redirected to the provider to authorize access, then returned to the Authentication settings page. After a successful link, the button will change to Disconnect. To unlink a provider, click Disconnect next to the connected account. Before disconnecting, make sure you still have another way to sign in (for example, a password or another linked provider) so you don't get locked out. # Managing applications with MCP Source: https://docs.rxresu.me/guides/managing-applications-with-mcp Use a connected MCP client to track job applications, attach sent PDFs, run Application Copilot, and manage your pipeline with natural-language prompts. Use this guide when you want an AI client to manage the **Application Tracker** for you. After the Reactive Resume MCP server is connected, the agent can use tools for the same application workflows available in the app: listing applications, creating records, importing rows, updating stages, adding notes, managing follow-ups, attaching documents, and running Application Copilot. ## Prerequisites Follow [Using the MCP server](/guides/using-the-mcp-server) to connect your MCP client with OAuth or an API key. Ask your client to list the Reactive Resume tools. You should see tools such as `list_applications`, `create_application`, `update_application`, `attach_application_document`, and `draft_application_message`. Tell your agent to ask before deleting applications, bulk-updating many records, or replacing attached documents. Application Copilot tools require the same AI provider setup used by the app. Match scoring and resume tailoring work best when the application has a linked Reactive Resume and a job description. ## Start with a pipeline review Have the agent inspect your current pipeline first. That gives it valid application IDs and avoids duplicate records. ```text theme={null} List my active applications grouped by stage. Include company, role, tags, follow-up date, linked resume name, and whether a resume or cover-letter PDF is attached. ``` Useful review prompts: ```text theme={null} Show me applications that need follow-up this week. ``` ```text theme={null} Find applications tagged remote that are still in saved or applied stage. ``` ```text theme={null} Summarize my pipeline stats by stage and source, then point out stale applications. ``` ```text theme={null} List archived applications from the last 90 days. ``` ## Create applications Use `create_application` when you already know the role details. ```text theme={null} Create an application for Senior Product Engineer at Acme. Stage: saved. Location: Berlin or remote. Source: LinkedIn. Tags: remote, typescript, senior. Add a note that I want to tailor my platform resume before applying. ``` If you have a job posting, ask the agent to extract details first. ```text theme={null} Use the Reactive Resume application auto-fill tool on this job posting URL, then create a saved application from the extracted company, role, location, salary, and job description. Tag it with remote and backend. ``` If the posting is private, paste the description into your prompt: ```text theme={null} Create an application from this pasted job description. Use auto-fill if available, keep the stage as saved, and tag it with ai, platform, and high-priority. [Paste the job description here] ``` ## Import applications Use `import_applications` when you already have spreadsheet rows. The Application Tracker accepts up to 500 imported rows at a time. ```text theme={null} Import these application rows into Reactive Resume. Normalize the stages to saved, applied, screening, interview, offer, or rejected. Skip rows that do not have both a company and role, and tell me what was skipped. Company,Role,Stage,Location,Source,Tags Acme,Frontend Engineer,applied,Remote,LinkedIn,remote;react Globex,Staff Engineer,interview,Berlin,Referral,staff;platform ``` ```text theme={null} I am pasting rows from my spreadsheet. Import them, tag every imported application with migrated-2026, and leave archived as false. ``` ```text theme={null} Import these rejected applications and mark them as archived after import. ``` ## Update stages and notes Use `update_application` for structured changes and `add_application_note` when you want an activity timeline entry without changing other fields. ```text theme={null} Move my Acme Senior Product Engineer application to interview and add a note: Recruiter screen scheduled for July 12 at 10:00. ``` ```text theme={null} Add a note to the Globex application: Submitted take-home assignment and waiting for review. ``` ```text theme={null} Set a follow-up date for the Stripe application to next Monday, with the note: Ask whether they need more portfolio examples. ``` ```text theme={null} Update the contacts on the Acme application. Recruiter: Priya Shah, priya@example.com. Hiring manager: Jordan Lee, LinkedIn URL https://www.linkedin.com/in/example. ``` ```text theme={null} Archive every rejected application older than 30 days, but show me the list and ask for confirmation before applying the bulk update. ``` ## Attach sent documents Use document attachment when you want the tracker to store the exact resume PDF or cover-letter PDF you sent for an application. ```text theme={null} Attach this PDF as the sent resume for the Acme application, then confirm the application now has a resume document. ``` ```text theme={null} Attach this cover letter PDF to the Globex Staff Engineer application. ``` ```text theme={null} Replace the resume PDF on the Stripe application with this updated PDF. Add a note that I resent the revised resume. ``` ```text theme={null} Remove the cover-letter PDF from the Acme application, but keep the application record and timeline. ``` `attach_application_document` accepts base64-encoded PDF bytes and `contentType: "application/pdf"`. Some MCP clients hide that detail when they can read local files. If your client cannot read local files, upload the PDF from the web app instead. ## Run Application Copilot Application Copilot tools let an agent use the same AI workflows available in the application detail panel. ```text theme={null} Score the resume linked to my Acme application against the saved job description. Summarize the biggest match gaps and do not change my resume. ``` ```text theme={null} Create a tailored resume copy for the Globex Staff Engineer application. Keep the original resume unchanged, link the tailored copy back to the application, and tell me the new resume name. ``` ```text theme={null} Draft a cover letter for the Stripe application using the linked resume and job description. Keep it concise and specific to the role. ``` ```text theme={null} Draft a follow-up email for the recruiter on the Acme application. Mention that I enjoyed the technical screen and ask about next steps. Do not mark the email as sent. ``` ```text theme={null} Review all interview-stage applications with linked resumes. For each one, score the match and list the top three tailoring opportunities. ``` Review AI-generated resumes, cover letters, and messages before sending them. MCP tools can draft and save context, but you are responsible for the final content. ## Maintain your pipeline Ask the agent to do periodic cleanup with explicit confirmation before broad changes. ```text theme={null} Find applications that have not changed in 21 days. Group them by stage and recommend which ones need a follow-up, archive, or no action. ``` ```text theme={null} Add the tag needs-follow-up to every active application with a follow-up date before today. Show me the list before updating. ``` ```text theme={null} Move all applications tagged offer to offer stage, unless they are already archived. ``` ```text theme={null} Archive rejected applications older than 60 days. Ask for confirmation before making changes. ``` ```text theme={null} Delete these duplicate application records after confirming which one has the most complete timeline and documents. ``` ## Prompt library Use these prompts as starting points. Replace company names, roles, tags, dates, and file references with your own details. ### Daily review ```text theme={null} Give me a daily application tracker brief. Include applications needing follow-up today, interviews coming up, stale saved roles, and any applications missing a linked resume. ``` ```text theme={null} Show my active applications in table form with company, role, stage, source, tags, follow-up date, and last updated time. ``` ```text theme={null} Which applications are missing job descriptions, contacts, sent resume PDFs, or cover-letter PDFs? ``` ### Research and capture ```text theme={null} Create a saved application from this job post. Extract company, role, location, salary, source URL, and job description. Add tags for the main technologies mentioned. ``` ```text theme={null} I am considering this role but have not applied. Add it as saved, link my backend resume, and add a note with the three reasons it looks relevant. ``` ```text theme={null} Add this recruiter contact to the matching application and note that they reached out on LinkedIn today. ``` ### Applying ```text theme={null} Move the Acme application from saved to applied. Set applied date to today, attach the resume PDF I sent, and add a note with the application portal confirmation number. ``` ```text theme={null} I just applied to three roles. Create applications for each one, tag them applied-today, and remind me to follow up in one week. ``` ```text theme={null} Find the best resume to link to this application based on role title and tags. Ask me before updating the application. ``` ### Interviews and follow-ups ```text theme={null} Move the Globex application to screening and add a recruiter screen contact with the recruiter's name and email. ``` ```text theme={null} Add a note that the onsite interview is scheduled for July 18. Set the follow-up date to July 19. ``` ```text theme={null} Draft a short follow-up after my interview. Use the application's company, role, recruiter contact, and timeline notes. ``` ### Reporting ```text theme={null} Summarize my job search this month: number applied, interviews, offers, rejections, top sources, and response rate. ``` ```text theme={null} Which sources are producing interviews? Compare LinkedIn, referrals, company sites, recruiters, and other sources. ``` ```text theme={null} Show applications by stage and tell me where the pipeline is blocked. ``` ## Suggested agent instruction Add this to your MCP client's project or session instructions when you want the agent to manage applications safely: ```text theme={null} Use Reactive Resume MCP for application tracking. Start by calling list_applications before creating a new record so you do not duplicate existing applications. Confirm before delete_application, bulk_delete_applications, bulk_update_applications, replacing attached documents, or archiving more than five applications. Prefer add_application_note for timeline updates. Use Application Copilot tools only when the application has enough context, and never present AI-generated cover letters or follow-ups as sent messages. ``` ## Troubleshooting | Issue | What to do | | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | The agent cannot see application tools | Reconnect the MCP server and ask the client to refresh tool discovery. Confirm you are connected to Reactive Resume v5.2.2 or later. | | The agent creates duplicates | Ask it to run `list_applications` first and match by company, role, and source URL before creating records. | | Document attachment fails | Attach only PDFs. If your MCP client cannot read local files, upload the document from the web app. | | Match scoring or tailoring fails | Link a Reactive Resume to the application and add a job description. Confirm your AI provider is configured. | | A bulk action changed too much | Use the application list and timeline to inspect what changed. For future sessions, require confirmation before bulk actions. | # Managing resumes from the dashboard Source: https://docs.rxresu.me/guides/managing-resumes-from-the-dashboard Search, sort, filter, open, duplicate, lock, update, and delete resumes from the Reactive Resume Resumes dashboard in grid or list view. The **Resumes** dashboard is where you manage every resume in your account. Use it to keep separate versions for different roles, clients, locations, or application stages. Resumes dashboard showing sort controls, grid view, create and import cards, and a sample resume ## Search your resumes Once you have more than a few resumes, a **Search** field appears above the list. Type any part of a resume name to filter the dashboard in place. You can also open the command palette from anywhere in the app with `Cmd/Ctrl+K`, or by clicking **Search** in the dashboard sidebar. From there you can jump to a resume, application, or agent thread by name, or run quick actions like **New Application** and **New Thread**. Select **Resumes**, **Applications**, or **Threads** to filter results to a single entity type. ## Choose a view The dashboard supports two views: * **Grid** shows each resume as a card. This is useful when you want a visual overview. * **List** shows resumes in rows. This is useful when you have many resumes and want a denser view. Use the **Grid** and **List** tabs in the top-right of the dashboard to switch between them. Resumes dashboard showing the same resume in list view ## Sort resumes Use the **Sort by** menu to change the order of your resumes. | Sort option | When to use it | | ---------------- | ----------------------------------------------- | | **Last Updated** | Find the resume you worked on most recently. | | **Created** | Review resumes by when they were first created. | | **Name** | Keep resumes in alphabetical order. | ## Filter by tags If you add tags to your resumes, the dashboard shows a **Filter by** menu. Select one or more tags to show only matching resumes. Tags are useful for grouping resumes by: * target role, such as `frontend` or `product`; * application status, such as `draft` or `sent`; * market, region, client, or company name. You can add or change tags when creating, updating, or duplicating a resume. ## Open a resume Click a resume card or row to open it in the builder. You can also open the resume menu and choose **Open**. After you create or import a resume, Reactive Resume opens it directly in the builder instead of returning you to the dashboard. ## Update name, slug, and tags Use **Update** when you want to change a resume's metadata. On the dashboard, open the menu for the resume you want to edit. Select **Update** to open the resume details dialog. Change the **Name**, **Slug**, or **Tags**. Click **Save Changes**. The slug is part of the public URL. If a resume is public, changing the slug changes the link people use to view it. ## Duplicate a resume Use **Duplicate** when you want to create a new version without changing the original. The duplicate dialog starts with the same tags, a copied name, and a copied slug. Edit these before saving if you want the new version to be easier to identify. Good reasons to duplicate a resume: * tailoring one resume for a specific job posting; * keeping a short and long version; * testing a new template or layout; * creating a localized version. ## Lock or unlock a resume Use **Lock** to prevent accidental edits or deletion. A locked resume cannot be updated or deleted until you unlock it. To edit a locked resume later, open the resume menu and choose **Unlock**. ## Delete a resume Use **Delete** only when you no longer need the resume. Deleting a resume cannot be undone. If you might need the content later, export a JSON backup first. See [Exporting your resume](/guides/exporting-your-resume). # Moving items between sections Source: https://docs.rxresu.me/guides/moving-items-between-sections Move resume items between sections or across pages in the Reactive Resume builder to reorganize content and split lengthy sections cleanly. If you have a long work history or a long list of projects, you may want to split items across multiple pages or reorganize them into different sections. The **Move to** feature relocates any item to another section or page. ## Why move items? * Split long sections. If your Experience section spans more than one page, move older roles to a custom section on page 2. * Reorganize content. Move a project from "Projects" to a custom "Open Source" section, or a skill to a different grouping. * Control the page layout. Choose exactly which items appear on which page. ## How to move an item Navigate to your resume and open it in the builder. Make sure you have at least one item in a section (e.g., an experience entry, project, or skill) before proceeding. In the left sidebar, find the section containing the item you want to relocate. Click on the section to expand it and view all items. Screenshot of the left sidebar with an expanded section containing multiple items Each item has a **dropdown menu** (three-dot icon or chevron) on the right side. Click this icon to reveal the available actions. Screenshot of the dropdown menu icon on a section item In the dropdown menu, hover over or click the Move to option. This will open a submenu showing all available destinations. The submenu displays available destinations organized by: * **Existing sections** of the same type (e.g., other Experience sections) * **Pages** where you can place the item * **Custom sections** if any exist Click on your desired destination to move the item there. Screenshot of the 'Move to' submenu with destination options If a custom section of the same type doesn't exist on your target page, Reactive Resume creates one for you, so you can split a section across pages without setting it up first. After selecting a destination, the item will be moved immediately. You can verify by: * Checking the destination section in the left sidebar * Looking at the resume preview to see where the item now appears Screenshot of the item in its new location ## Example: splitting work experience across pages A common case is a work history that is too long to fit on a single page. Review your Experience section and decide which roles should appear on page 1 (typically your most recent and relevant positions) and which can go on page 2. For each older position you want to relocate: 1. Open the item's dropdown menu 2. Click Move to 3. Select **Page 2** (or the appropriate page) If no Experience section exists on page 2, a new custom section will be created automatically with the same type, so your formatting stays consistent. Check the resume preview to ensure: * Page 1 contains your most important, recent roles * Page 2 continues with your earlier experience * The section headings and styling remain consistent ## Tips for organizing multi-page resumes Keep chronological order within each page, and move complete job entries rather than splitting a single role across pages. After moving items to a new custom section, rename it (e.g., "Earlier Experience" or "Additional Projects") so recruiters know what they are looking at. Moving items reorganizes your content but doesn't change the data itself. You can always move items back, or to a different section. ## Troubleshooting ### I don't see the "Move to" option Make sure you're clicking the dropdown menu on a **section item** (like an individual job or project), not the section header itself. The Move to feature is only available for items within sections. ### The destination I want isn't listed The Move to submenu shows destinations compatible with the item type. For example, an Experience item can only be moved to other Experience-type sections. If you need to change an item's type entirely, recreate it in the section you want. ### My custom section wasn't created If you're moving to a page that already has a section of the same type, the item will be added to that existing section rather than creating a new one. This is by design to avoid duplicate sections. # Selecting the right page format Source: https://docs.rxresu.me/guides/selecting-page-format Compare the A4, Letter, and Free-Form page format options in Reactive Resume and pick the right size, margins, and orientation for your resume. Reactive Resume has three page formats: **A4**, **Letter**, and **Free-Form**. The format you pick changes how your resume is rendered and exported as a PDF. ## Available formats ### A4 A4 is the international standard paper size used in most countries outside North America. When you select A4, your resume pages conform to these dimensions: | Property | Value | | -------- | -------------- | | Width | 210mm (794px) | | Height | 297mm (1123px) | Choose A4 if you're applying to jobs internationally or in regions that use the metric system. ### Letter Letter is the standard paper size in the United States and Canada. When you select Letter, your resume pages conform to these dimensions: | Property | Value | | -------- | -------------- | | Width | 216mm (816px) | | Height | 279mm (1056px) | Choose Letter if you're applying to jobs in North America. ### Free-Form Free-Form is built for resumes that are only read on a screen. Instead of matching a physical page size, it produces a **single continuous page** with no height limit. The width matches A4 (210mm), and the height extends to fit all your content. | Property | Value | | -------- | ------------- | | Width | 210mm (794px) | | Height | Unlimited | With Free-Form, there are no page breaks. Your resume renders as one continuous document, no matter how much content you have. ## Why Free-Form exists Most resumes are never printed. Yours is almost always read digitally: on a screen, in an applicant tracking system (ATS), or by an AI screening tool. When your resume is processed digitally: * ATS parsers extract the text regardless of page dimensions * AI scanners analyze the full document as a single unit * Recruiters scroll through PDFs on their screens rather than printing them * PDF parsing tools read the whole file regardless of page height Since physical page limits no longer apply in those cases, Free-Form lets you focus on the content instead of fitting it into a fixed page height. If you don't plan on printing your resume, Free-Form is usually the simplest choice. Nothing overflows, and there are no awkward page breaks. ## How to change your page format Navigate to your Dashboard and click on the resume you want to edit. The sidebar sits on the right edge of the resume builder. In the right sidebar, find and click on the **Page** section to expand it. Find the **Format** dropdown and select your preferred option: A4, Letter, or Free-Form. Screenshot of the Format dropdown in the Page section Your resume preview updates immediately to reflect the new format. Check that your content displays correctly. ## Choosing the right format | Situation | Recommended Format | | --------------------------------------- | ------------------ | | Applying to jobs in North America | Letter | | Applying to jobs internationally | A4 | | Digital-only applications (no printing) | Free-Form | | Uploading to ATS or job portals | Free-Form | | Need to print physical copies | A4 or Letter | | Long resume with lots of content | Free-Form | | Traditional industries (law, finance) | A4 or Letter | If you switch from Free-Form to A4 or Letter, your content is split across multiple pages. Review the result and check that the page breaks don't fall in awkward places. ## Example PDFs Download these sample resumes to see how different formats affect the final PDF output: A sample resume in A4 format showing traditional page breaks and constraints. A sample resume in Free-Form format showing a continuous single-page layout. ## Frequently asked questions Yes. An ATS parses the text in your PDF, not the page dimensions. Free-Form resumes work with applicant tracking systems. Yes. You can change the format at any time from the Page section in the right sidebar. Your content is preserved. Only the layout changes. If the employer asks for a one-page resume and expects a traditional format, use A4 or Letter and fit your content on a single page. See [Fitting content on a page](/guides/fitting-content-on-a-page) for tips. Slightly. A longer single page may produce a marginally larger PDF than a paginated version of the same content, but the difference is negligible for typical resume lengths. LinkedIn doesn't display uploaded resumes in their original format; it extracts the content. Free-Form works fine for LinkedIn uploads. # Setting up passkeys Source: https://docs.rxresu.me/guides/setting-up-passkeys Register WebAuthn passkeys on your Reactive Resume account to sign in with biometrics, a device PIN, or a security key instead of a password. Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials. In the dashboard sidebar on the left, under Settings, click the Authentication link. In the Passkeys section, click the Register New Device button. Enter a descriptive name so you can recognize it later (for example, "MacBook Touch ID" or "iPhone Face ID"). Your browser or device shows a passkey prompt (WebAuthn). What it asks for depends on the authenticator you are registering: a biometric (Face ID / Touch ID / fingerprint), your device PIN, or inserting and touching a security key. Passkeys are tied to your device (or password manager) and are a more secure alternative to passwords. After registering, your passkey appears in the list. You can rename it or delete it from the same section. Deleting a passkey cannot be undone. After deletion, you won't be able to sign in using that passkey anymore. On the login page, click Sign in with Passkey to authenticate without entering your password. # Setting up two-factor authentication Source: https://docs.rxresu.me/guides/setting-up-two-factor-authentication Enable TOTP two-factor authentication on your Reactive Resume account with an authenticator app, save recovery codes, and manage 2FA settings. The option to set up two-factor authentication only appears once your account has a password. If you signed in with Google or GitHub and never set one, you cannot follow this guide until you do. Two-factor authentication requires a password to be set on your account. If you signed up using a social provider (Google or GitHub), you'll need to set a password first from the Authentication settings page. Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials. If you haven't created an account yet, follow the guide on [Creating an account](/guides/creating-an-account). In the dashboard sidebar on the left, under Settings, click the Authentication link. On the Authentication page, find the Two-Factor Authentication section and click the Enable 2FA button. You are asked to re-enter your password to confirm it's really you. Enter it and click continue. The password check prevents someone else from enabling two-factor authentication on your account. After entering your password, you are shown a QR code. Scan it with your authenticator device and enter the 6-digit code the app gives you to continue. Popular authenticator apps you can use include: * **Google Authenticator** - Available on iOS and Android * **Microsoft Authenticator** - Available on iOS and Android * **Authy** - Available on iOS, Android, and desktop * **1Password** - Available on multiple platforms * **LastPass Authenticator** - Available on iOS and Android If you prefer manual entry, copy the secret key above the QR code and paste it into your authenticator app. Once verified, you are prompted to save backup codes. Each code works only once, and they let you sign in if you lose access to your authenticator device. Make sure to copy and store these backup codes in a safe place. If you lose your authenticator device and don't have backup codes, you may lose access to your account. The next time you sign in, you are asked for a one-time code from your authenticator app. Enter the 6-digit code shown there to finish signing in. If you have lost access to your authenticator device, use one of your backup codes to sign in. Each backup code can only be used once. # Sharing your resume publicly Source: https://docs.rxresu.me/guides/sharing-your-resume-publicly Publish your resume at a public URL, share it with recruiters, track views and downloads, and optionally protect it with a password. Reactive Resume can publish your resume at a **public URL**. Anyone with the link can open it, so you can send it to recruiters, collaborators, or people visiting your portfolio. Public resume URLs are not search-indexed by default. ## What public sharing gives you Viewers always see the latest version of your resume. No need to send new files when you make updates. See public view counters in the builder. Optionally require a password so only people you trust can access your resume. One URL you can paste into an email signature, LinkedIn, a portfolio, or a job application. ## How to enable public sharing Navigate to your resume in the resume builder. In the **right sidebar**, select **Sharing**. Turn on the **Allow Public Access** switch. Your resume is then reachable at its public URL. Sharing section showing the public access control Your public URL is displayed below the toggle. It follows this format: ``` https://rxresu.me/{username}/{slug} ``` Click the **copy** button to copy the URL to your clipboard. The `{slug}` is the unique, URL-safe name you assign to your resume when you create it. If you want to change your slug, go to the dashboard, right-click your resume card, and choose "Update" to edit its details. ## How the public URL works When someone visits your public resume URL: 1. They see the live version. The page renders your current resume data, including your latest changes. 2. No account is required. Visitors don't need a Reactive Resume account to view or download your resume. 3. They can download a PDF. The public page shows an identity header with your name, headline, and picture, plus a **Download PDF** action. 4. Link previews work. Reactive Resume generates per-resume Open Graph and Twitter card previews, so links you paste into LinkedIn, Slack, iMessage, and similar apps show your name and headline instead of a generic placeholder. 5. Views are tracked. Visits are counted in your resume statistics (see below). Changes you make in the builder show up immediately on the public URL. There is no separate "publish" step. Treat the link as something you send to people directly, not as a search profile page. ## Resume language Set **Page → Language** in the builder's right sidebar to choose the language of default section headings. Public visitors and PDF downloads use this saved resume language, even when the visitor's app interface uses another language. Section titles you rename remain as written. The interface language selected in Preferences is stored in the current browser. It does not change the resume's language or sync to other browsers. ## Tracking public engagement When your resume is public, Reactive Resume counts public views, so you can tell whether people are opening the link you shared. ### Where to find statistics In the resume builder, open the **right sidebar** and select **Statistics**. You'll see public view information such as: | Metric | Description | | --------------- | --------------------------------------------------------- | | **Views** | Number of times your public resume page was visited | | **Downloads** | Number of times a visitor downloaded your resume as a PDF | | **Last viewed** | The date when your resume was last viewed | Each metric also shows a 30-day sparkline and the change against the previous period, so you can see whether interest rose or fell after you shared the link. Statistics are only shown after public sharing is enabled. If you turn off public access, existing stats are preserved. ### What counts as a view? A view is counted each time someone loads your public resume page. This includes: * Direct visits to your public URL * Clicks from links you've shared Owner self-visits while you are signed in to your account are not included in the view statistics. Only **you** can see your resume's view statistics. Visitors to your public URL cannot see how many views your resume has. ## Password protecting your resume To share your resume with specific people while keeping it away from everyone else, add password protection. When password protection is enabled: * Visitors must enter the correct password to view your resume * The password prompt appears before any resume content is shown * You can share the password separately with trusted individuals ### How to set a password First, make sure **Allow Public Access** is turned on in the **Sharing** section. Below the public URL, click **Set Password**. Type a password (6-64 characters) and confirm it. Viewers have to enter this password to see your resume. Share the password with your intended audience through a secure channel (e.g., direct message, email). Choose a password you're comfortable sharing. Anyone with the password can view and download your resume. ### How to remove password protection If you no longer need password protection: 1. Go to the **Sharing** section in the right sidebar 2. Click **Remove Password** 3. Confirm the action Your resume is then open to anyone with the public URL. ## Use cases for public sharing Add your public resume URL to your LinkedIn profile's **Featured** section or **Contact Info**. Recruiters can view your detailed resume directly. Include your resume link in your email signature, so anyone you write to can open it. Embed or link to your resume from your personal website. The link always shows your latest resume. Some applications accept a link to your resume, while others require a file upload. Use the public URL when a link is accepted, and export a PDF when an upload is required. Share your resume URL via QR code or NFC. Update the resume before the event and everyone gets the current version. Use password protection to share your resume only with specific recruiters while keeping it hidden from your current employer. ## Turning off public access To make your resume private again: 1. Go to the **Sharing** section in the right sidebar 2. Turn off the **Allow Public Access** switch When public access is disabled: * Your public URL returns a "not found" error * Existing links stop working immediately * Your statistics are preserved (they'll resume if you re-enable public access) * Password protection settings are preserved To hide your resume temporarily, use password protection instead of turning off public access. The URL stays active for people who have the password. ## Copying the URL from the builder dock The builder dock has a **Copy URL** shortcut. It copies the same public URL shown in the **Sharing** section. Copying the URL does not enable public access. Turn on **Allow Public Access** in the **Sharing** section before sending the link to someone else. ## Frequently asked questions Yes. The URL is based on your **username** and the resume's **slug**. You can change the slug in the **Update Resume** dialog. To open it, right-click your resume card in the dashboard and select "Update". The username is set in your account settings. No. By default, public resume URLs are meant for human recipients who receive the link from you, not as search profile pages. If you want tighter access control, use password protection or keep your resume private. No. If you are signed in as the owner, your own visits are excluded from the view statistics. No, Reactive Resume tracks public view counts, not the identity of visitors. This protects visitor privacy. Your public URL changes to match the new username, and the old URLs stop working immediately. Update any links you have already shared. # Tracking job applications Source: https://docs.rxresu.me/guides/tracking-job-applications Use the Application Tracker to record jobs, link the resume you sent, manage follow-ups, and move applications through your hiring pipeline. The **Application Tracker** keeps your job search tied to the resumes you build in Reactive Resume. Each application can store the company, role, stage, job posting, resume, cover letter, contacts, notes, and follow-up details. ## Open the Application Tracker Open Reactive Resume and sign in to your account. In the dashboard sidebar, click **Applications**. Application Tracker showing search, tag filters, board columns, and application cards grouped by stage Press `Cmd/Ctrl+K` from anywhere in the app to open the command palette. Select **Applications** to search your pipeline by company or role, or run **New Application** to jump straight to the add form. ## Add an application If this is your first application, use the button in the empty state. Otherwise, use **Add application** in the page header. Add the **Company** and **Role / title**. These two fields are required. You can also add the location, salary range, source, tags, notes, and follow-up details. Pick the current stage of the opportunity. Pick a Reactive Resume in the **Resume** field to keep a live link to it. You can also upload the exact resume PDF you sent. If you sent a cover letter, attach the PDF in the **Cover letter** field. Click **Add to pipeline**. Add application form with job posting auto-fill, company, role, stage, resume, cover letter, tags, and follow-up fields Linking a Reactive Resume enables AI match scoring and resume tailoring for that application. ## Use AI to fill a job posting If you have an AI provider configured, paste a job posting URL at the top of the add form and click **Auto-fill**. Reactive Resume reads the posting and fills in what it can, such as company, role, location, salary, and job description. If auto-fill fails or the posting is private, paste the job description manually. For AI setup, see [Using artificial intelligence](/guides/using-ai). ## Understand application stages Applications move through a fixed set of stages: | Stage | Use it when | | ------------- | ------------------------------------------------------------------- | | **Saved** | You found a role but have not applied yet. | | **Applied** | You submitted the application. | | **Screening** | A recruiter, hiring manager, or automated process is reviewing you. | | **Interview** | You are in an interview process. | | **Offer** | You received an offer. | | **Rejected** | The company declined or the opportunity ended. | You can move applications by dragging cards on the board, using the action menu, using bulk actions in the table, or opening an application and clicking **Move to**. ## Choose a view The Application Tracker has three views: | View | Best for | | ------------ | -------------------------------------------------------------------------------------------------- | | **Board** | Moving applications through stages visually. | | **Table** | Reviewing many applications, selecting rows, and making bulk updates. | | **Insights** | Understanding your pipeline, response rate, interviews, offers, sources, and application velocity. | Use search, tag filters, sorting, and the archived toggle to narrow the list. Application Tracker insights view showing pipeline metrics, a funnel chart, applications over time, and source counts ## Update an application Open an application from the board or table to view its detail panel. From there you can: * edit the application details; * move it to the next stage; * open the original job posting; * attach or replace resume and cover letter PDFs; * add contacts; * add follow-up information; * add notes to the timeline; * archive, unarchive, mark rejected, or delete the application. Stage changes and notes appear in the timeline automatically. Application detail panel showing stage progress, linked resume, Application Copilot, contacts, and timeline activity ## Use Application Copilot Application Copilot appears in the application detail panel. It can: * score how well the linked resume matches the job description; * create a tailored copy of the linked resume; * draft a cover letter; * draft a follow-up message. Match scoring and resume tailoring require both a linked Reactive Resume and a job description. Drafting also works from the application and resume context available in the tracker. Review AI-generated content before sending it. You are responsible for the final resume, cover letter, and follow-up message. ## Manage applications from an MCP client You can also manage the Application Tracker from an MCP-compatible AI client. This lets an agent list applications, create new records, move stages, add notes, attach the PDFs you sent, and run Application Copilot without opening the web app. For setup and prompt examples, see [Managing applications with MCP](/guides/managing-applications-with-mcp). ## Archive or delete applications Archive an application to hide it from the active board without losing its history. Use the **Archived** toggle to see archived applications and unarchive them later. Delete an application only when you no longer need its record. Deleting an application removes its timeline and cannot be undone. # Undoing changes and version history Source: https://docs.rxresu.me/guides/undoing-changes-and-version-history Undo and redo edits with keyboard shortcuts in the Reactive Resume builder, and restore an earlier snapshot from the version history menu. Reactive Resume keeps two layers of change history for every resume: * **Undo and redo**: a live timeline of the changes you've made in the current builder session. * **Version history**: server-side snapshots taken at meaningful moments, kept even after you close the builder. Use undo for a quick correction. Use version history to jump back to an earlier editing snapshot, import, or AI/API edit. ## Undo and redo Every change in the builder is undoable: typing, drag-and-drop reordering, template and layout switches, and edits applied by the AI assistant. Undo history is scoped to the resume you have open. Use either the toolbar buttons on the floating dock or a keyboard shortcut: | Shortcut | Action | | ------------------ | --------------------------- | | `Cmd/Ctrl+Z` | Undo the last change | | `Cmd/Ctrl+Shift+Z` | Redo the last undone change | Rapid typing collapses into a single step, so one undo removes a phrase rather than one letter. When your cursor is inside a text field, `Cmd/Ctrl+Z` falls back to your browser's native input undo, so you can undo just the characters you typed. Click outside the field, or use the dock buttons, to undo builder-wide changes such as a template switch. Undo history lives in your browser for the current session. Reloading the builder clears it, so use version history for anything older. ## Version history Reactive Resume snapshots your resume automatically: * when you import a resume; * when the AI assistant or API applies edits; * on periodic saves during editing, including template switches; * when you restore a version. Snapshots are stored on the server, per resume, and are kept across sessions. Reactive Resume keeps a rolling window of the 30 most recent snapshots for each resume. Periodic editing snapshots, including template changes, are throttled to at most one every two minutes. Imports, AI/API edits, and restores create their own checkpoints. ### Open version history Click the **clock** icon in the builder header, next to the resume name, to open the version history menu. The menu lists recent snapshots newest first, each with a label describing what triggered it and a relative timestamp such as *2 hours ago*. ### Restore a version Click the clock icon in the builder header. Select the entry you want to restore. Reactive Resume asks you to confirm before replacing the current data. The resume is updated to the snapshot's contents and reloads in the preview. Restoring is **non-destructive**: it writes the older snapshot back through the normal update path, so: * your previous versions are still listed in the menu; * the restore itself becomes a new snapshot; * if you change your mind, you can restore the pre-restore version, or press `Cmd/Ctrl+Z` to undo the restore. Only the resume owner can list or restore versions. A locked resume cannot be edited or restored until you unlock it from the dashboard. ## Keep longer owner-managed history with Git In-app version history and Git backups solve different problems: * **In-app version history** is automatic, stored by Reactive Resume, and limited to the 30 most recent rolling snapshots for one resume. * **Git history** contains only the JSON exports you choose to commit. It is stored in your own local repository, uses your commit messages, and follows the retention you choose. Git backup is manual. Reactive Resume does not create commits, synchronize with a repository, or upload files to a remote. To set up a local repository and recover a committed export as a new resume, see [Keep JSON backups in a local Git repository](/guides/exporting-your-resume#keep-json-backups-in-a-local-git-repository). ## Which to use when | Situation | Use | | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | You typed a wrong word or moved an item you didn't mean to. | Undo (`Cmd/Ctrl+Z`) | | You just switched templates and want the old one back. | Undo; version history can help only after a periodic editing snapshot captures the switch. | | You imported a resume and want to compare with what you had before. | Version history | | The AI assistant applied edits you no longer want. | Undo the batch, or restore the pre-AI snapshot. | | You closed the browser and want to roll back yesterday's changes. | Version history | | You want selected backups beyond the 30-snapshot rolling window. | Export JSON and commit it to your own Git repository. | # Updating your profile Source: https://docs.rxresu.me/guides/updating-your-profile Update your Reactive Resume profile information, including your display name, username, email address, and profile picture from account settings. Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials. If you haven't created an account yet, follow the guide on [Creating an account](/guides/creating-an-account). In the dashboard sidebar on the left, under Settings, click the Profile link. On the Profile page, you can update the following information: * **Name**: Your full name as it appears in your account * **Username**: Your unique username (used in public resume URLs) * **Email Address**: Your account email address If you update your email address, you will receive a verification link on your current email address. The change will only be accepted after you click on the verification link. If you've updated your email address, check your current email inbox for a verification link. Click on the link to confirm the email change. Check your spam folder if the verification email isn't in your inbox. The email address change only completes after you click the link. # Using artificial intelligence Source: https://docs.rxresu.me/guides/using-ai Configure an OpenAI, Anthropic, Gemini, OpenRouter, or Ollama provider to power AI edits, resume reviews, agent drafts, and PDF imports. Reactive Resume uses AI providers for features such as AI-assisted resume changes, the optional AI review in the ATS checker, AI agent drafts, and PDF or Word imports. ## Open AI provider settings Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials. In the dashboard sidebar, under **Settings**, click **Integrations**. Integrations settings showing AI provider configuration ## Add a provider In the **AI Providers** section, fill out the **Add Provider** form. The form is staged: pick a **Provider** and paste an **API Key** first. **Model** and **Base URL** sit behind the **Advanced settings** toggle, and you only need them for gateways, proxies, local providers, or OpenAI-compatible endpoints. | Field | Description | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | **Label** | A name that helps you recognize the provider, such as `Work OpenAI` or `Personal OpenRouter`. | | **Provider** | The provider type, such as OpenAI, Anthropic Claude, Google Gemini, Vercel AI Gateway, OpenRouter, Ollama, or OpenAI-compatible. | | **API Key** | The key Reactive Resume should use when sending AI requests to that provider. | | **Model** *(advanced)* | The exact model name expected by that provider. | | **Base URL** *(advanced)* | The provider endpoint. Leave the default unless you use a gateway, proxy, local provider, or OpenAI-compatible endpoint. | Click **Save Provider** when the form is complete. The connection is tested as part of the save, so the success or failure status appears right away. Integrations settings showing a saved and tested AI provider Treat API keys like passwords. Anyone with a key can use the connected provider account and may incur costs. ## Test and enable a provider After saving a provider, test it before using it. Reactive Resume sends a small request to verify the provider, model, base URL, and key. A successful provider is marked **Tested**. A failed provider is marked **Failed** and may show an error message. Turn on **Use** for the tested provider you want Reactive Resume to use. Only tested providers can be used for AI-assisted features. ## How credentials are stored AI provider credentials are encrypted on the server and are never shown again after saving. The settings page only shows a preview of the saved key. If provider management is unavailable, your self-hosted deployment may be missing required server configuration. AI provider management requires the server-side services used to encrypt credentials. If the page says provider management is unavailable, check your deployment configuration before using AI features. ## Where AI is used After a provider is tested and enabled, you can use AI in: * the optional **AI review** in the ATS Check section of the builder's right sidebar; * **AI-assisted resume changes** from the builder; * **Agent** workflows that create isolated AI drafts; * **PDF and Microsoft Word imports** from the dashboard import dialog. For the builder workflow, see [Using AI in the builder](/guides/using-ai-in-the-builder). For the dedicated agent workspace, see [Using the AI Agent workspace](/guides/using-ai-agent) and [AI Agent tools](/guides/ai-agent-tools). For AI-assisted imports, see [Importing resumes](/guides/importing-resumes). # Using the AI Agent workspace Source: https://docs.rxresu.me/guides/using-ai-agent Start an isolated AI draft in the Reactive Resume Agent workspace, chat with the agent, review proposed resume patches, and resume prior threads. The AI Agent workspace is where you work with an AI assistant on a resume draft. It keeps the conversation, the tool activity, and a read-only resume preview in one full-screen view. Agent threads edit an AI draft copy of your resume. Your original resume is not changed when you start from an existing resume. ## Before you start You need at least one AI provider that is tested and enabled in **Dashboard → Settings → Integrations**. For setup, see [Using artificial intelligence](/guides/using-ai). If you self-host Reactive Resume, the agent workspace also requires the server-side agent configuration described in [Self-hosting with Docker](/self-hosting/docker). ## Open the agent workspace From the dashboard sidebar, click **Agents**. The agent page always shows your thread sidebar. Use it to continue an existing thread, or click **New thread** to start another one. You can also open the agent from the builder dock. When you do this, the current resume is preselected in the new thread setup screen. Press `Cmd/Ctrl+K` from anywhere in the app to open the command palette. Select **Threads** to search existing threads by title, resume, or provider, or run **New Thread** to jump straight to the setup screen. ## Start a new thread Pick the provider/model combo the agent should use. This choice is locked once the thread starts. Select an existing resume to duplicate as an AI draft, or choose **Create from scratch** for a blank draft. Click **Start Thread** to create the draft and open the workspace. AI Agent new thread setup with model and resume selectors ## Use the three-pane workspace The desktop workspace is split into three panes: * **Threads** on the left: continue, archive, delete, or start agent threads. * **Chat** in the center: send prompts, upload files, answer agent questions, and review tool activity. * **Resume** on the right: read the current AI draft, adjust zoom, open it in the builder, or download a PDF. AI Agent workspace showing thread sidebar, chat, and resume preview On smaller screens, the workspace uses tabs/sheets so you can switch between threads, chat, and preview without losing the active conversation. ## Ask for resume changes The agent works best with concrete instructions: * "Tailor this resume to this job description: `https://example.com/job`" * "Find weak bullets and rewrite them with stronger outcomes." * "Compare this draft against a product manager role and update the keywords." * "Ask me before changing anything that looks uncertain." You can attach files or images from the composer. The agent reads uploaded attachments when they are relevant to your request. For supplied text, paste the content directly into the chat. Plain text, Markdown, and JSON attachments are available to the agent as extracted text. Images and supported files such as PDFs are passed directly to the selected provider when it can use them. If an attachment format is unsupported by the selected provider, paste the relevant text instead. Text input is supported. Voice input is not supported in the agent workspace yet. ## Tailor a resume to a supplied job description Use this controlled workflow to test tailoring without relying on live web research: In **Dashboard → Settings → Integrations**, configure a supported AI provider, test it, and make sure it is enabled. Then return to **Agents**. Start a new thread and select a resume containing sample experience data. The agent creates an isolated AI draft, so the source resume remains unchanged. Paste this sample job description into the chat: ```text theme={null} Target role: backend engineer. Required: TypeScript and PostgreSQL. ``` Then ask: "Tailor the existing experience for this role. Do not invent qualifications or experience." Review the updated draft. To approve patches before they are applied, inspect their JSON, or restore an earlier state, follow [Review edits and patches](#review-edits-and-patches). This workflow also works when the selected provider/model has no live web search. Supplying the job description gives the agent the context it needs for ordinary resume editing. ## Review edits and patches By default, the agent applies resume patches immediately to the AI draft. Turn on **Review edits** in the thread menu if you want to approve or deny patches before they are applied. Applied patches appear in chat as a small **Patch applied** line. Open the line to inspect the raw JSON Patch and use **Restore** if you want to roll the draft back to the state before that patch. Restoring an older patch also rolls back patches applied after it. AI-generated changes can still be inaccurate. Review the draft in the preview or builder before exporting or sharing it. ## Answer agent questions If the agent needs a decision, it may show a question card with recommended answers. Click the answer you want to send it back to the agent. That happens when your instructions are ambiguous, job context is missing, or a change depends on your preference. ## Use the resume preview The resume pane is read-only. Use the toolbar to: * decrease or increase zoom; * set an exact zoom percentage; * open the AI draft in the builder; * download the draft as a PDF. Zoom settings are remembered across refreshes. ## Manage threads Threads are ordered by the newest message. Use the thread menu to archive or delete a thread. * **Archive** keeps the conversation but makes the thread read-only. * **Delete** removes the thread conversation and its attachments. The generated resume draft remains in your dashboard. Threads can also become read-only if the working resume is deleted, the selected provider is deleted, or the thread is archived. If a provider is disabled or no longer tested, re-enable and test it before sending new messages. # Using AI in the builder Source: https://docs.rxresu.me/guides/using-ai-in-the-builder Chat with the built-in AI assistant in the builder to review proposed resume changes before applying them, and add an optional AI review to the ATS check. Reactive Resume includes two AI-assisted builder workflows: * The **AI assistant** opens as a side panel in the builder, scoped to the open resume, so you can chat and apply edits inline. * The **ATS Check** section can add an optional AI review of your writing on top of its deterministic report. These features require a tested and enabled AI provider in **Dashboard → Settings → Integrations**. For setup, see [Using artificial intelligence](/guides/using-ai). ## Review the writing from the ATS check The **ATS Check** section in the right sidebar runs without AI: its checks are deterministic and run in your browser. Once a deep check has produced a report, it offers an optional AI review of the writing: weak phrasing, bullets that describe duties rather than outcomes, and where a rewrite would land better. The review sends the text already extracted from your rendered PDF to the provider you pick, and returns no score. See [Using the ATS checker](/guides/using-the-ats-checker). ## Open the AI assistant Click the **Sparkle** button in the builder header, next to the resume name, to open the assistant. The assistant opens as a side panel next to your resume. It uses the same chat interface as the AI Agent workspace, but stays scoped to the resume you are editing. Its edits land in the builder immediately, appear in the preview, and are captured in undo history and version history. If AI is unavailable, the panel shows a link to **Integrations** so you can configure a provider. The Sparkle button is the in-builder assistant. The chat-bubble icon on the floating dock opens the full **AI Agent** workspace in a new page, which suits longer, standalone conversations that create their own draft. See [Using the AI Agent Workspace](/guides/using-ai-agent). ## Ask for targeted changes The assistant works best when you ask for specific, incremental changes. Good prompts: * "Rewrite my summary for a senior frontend engineer role." * "Tighten the bullets in my most recent job." * "Add measurable impact to my project descriptions." * "Adapt this resume for the job description below." Avoid asking it to rewrite everything at once unless you are prepared to review many changes. ## Review proposals before applying them When the assistant proposes edits, Reactive Resume shows a review card with: * a proposal title and summary; * badges for the proposed operations; * before and after previews; * the raw JSON Patch for users who want to inspect the exact operations. You can: * **Accept** one proposal; * **Reject** one proposal; * move between proposals with **Prev** and **Next**; * **Accept all** or **Reject all** from the split-button menu. Accepted edits are saved through the normal update path, so they show up in the preview, in undo history, and in version history. If you change your mind, use `Cmd/Ctrl+Z` or restore an earlier snapshot from the clock menu. See [Undoing changes and version history](/guides/undoing-changes-and-version-history). Review AI proposals before accepting them. AI can introduce wording that is inaccurate, too generic, or not aligned with your actual experience. ## When a proposal cannot be applied A proposal can fail if the resume changed after the assistant generated it, if the resume is locked, or if the proposed patch no longer matches the current resume data. If that happens, ask the assistant to regenerate the change from the latest version of the resume. # Using private notes Source: https://docs.rxresu.me/guides/using-private-notes Use the private notes section in Reactive Resume to track job applications, company details, and other personal reminders for each resume. ## What are private notes? The **Notes** section stores personal information about one resume. Nothing you write there appears on the resume itself, whether it is viewed publicly or exported as a PDF. It is a notebook attached to each resume, where you can jot down anything relevant to your job search. Your notes are stored with that resume's data and are only visible to you when editing the resume. ## Where to find it In the resume builder, open the **right sidebar** and select **Notes** from the available sections. Screenshot of the Notes section in the right sidebar ## Use cases Some practical ways to use them: ### Track job applications Keep a record of where you've sent this particular resume: * Company names and positions applied for * Application dates and deadlines * Recruiter or hiring manager contact information * Application status (submitted, interviewing, offer, rejected) ### Save job description links Paste links to the original job postings so you can quickly reference them when preparing for interviews or following up. Job postings often come down once a position is filled. Copy the main requirements or responsibilities into your notes as a backup. ### Interview preparation Keep notes to help you prepare: * Questions you want to ask the interviewer * Key points to highlight from your experience * Salary expectations and negotiation notes * Company research and talking points ### Version control reminders If you maintain multiple versions of your resume, use notes to remind yourself: * What makes this version unique * Which types of roles this resume is tailored for * What was changed from your base resume ### Follow-up reminders Track your follow-up schedule: * When you last followed up with a company * Next steps and deadlines * Response notes from recruiters ## How to use it In the resume builder, click on **Notes** in the right sidebar to expand the section. Use the rich text editor to write your notes. You can format text with bold, italics, bullet points, and more. Your notes are saved automatically as you type. There's no need to click a save button. ## Privacy guarantee Your notes are for your eyes only. They will **never** appear in your exported files, on your public resume URL, or in a printed version of your resume. That makes it safe to store sensitive details: salary expectations, candid thoughts about an opportunity, or reminders you would not want an employer to see. ## Tips for effective note-taking * Use a similar format across all your resumes, so information is easy to find * Add dates when you note an application submission or a follow-up * Keep the notes specific to this version of the resume and the roles it targets * Update them as your job search moves along # Using the API Source: https://docs.rxresu.me/guides/using-the-api Create Reactive Resume API keys, authenticate REST requests with bearer tokens, and integrate resume data into your own scripts, apps, or automations. Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials. In the dashboard sidebar on the left, under Settings, click the API Keys link. On the API Keys page, click API Documentation to open the API reference. You can also open it directly here: [API Reference](https://docs.rxresu.me/api-reference). Click Create a new API key. Fill in: * **Name**: A label to help you identify what you use this key for * **Expires in**: How long the key should remain valid The secret key is shown once, right after you create it. Copy it and store it somewhere safe. For security reasons, your API key is only displayed once. If you lose it, you must create a new one. To authenticate API requests, include your key in the x-api-key header. If you're self-hosting, replace [https://rxresu.me](https://rxresu.me) with your instance URL. The API is served under /api/openapi. ```bash theme={null} curl "https://rxresu.me/api/openapi/resumes" \ -H "x-api-key: YOUR_API_KEY" ``` In the API Keys list, click the trash icon next to a key and confirm deletion. Deleted API keys stop working immediately, and the action cannot be undone. # Using the ATS checker Source: https://docs.rxresu.me/guides/using-the-ats-checker Check whether an applicant tracking system can read your resume PDF, from the free public page or from inside the builder, without uploading the file anywhere. The ATS checker answers one question: **can software read your resume?** It opens your PDF the way a parser would, pulls the text out, and reports what survived and what did not. Everything runs in your browser. The file is never uploaded, nothing is stored, and no account is needed. Use it at [rxresu.me/ats-checker](https://rxresu.me/ats-checker), or from the **ATS Check** section in the builder's right sidebar. ## What it measures * Whether the file carries real text, or is a picture of one. * Whether the text extracts in the order a person reads it, which is where multi-column layouts usually fail. * Whether your name, email, phone number, links, and dates survive extraction intact. * Whether the conventional sections are present and can be told apart. * Whether the file itself is readable: fonts, encryption, forms, size, page geometry. Optionally, paste a job description and it will tell you which of the posting's terms already appear in your resume. ## What it does not measure No tool can tell you whether an application will be rejected. That depends on the role, the screening questions, and the person reading. Anything that claims otherwise is guessing. The checker deliberately does not: * repeat the widely quoted claim that most resumes are discarded automatically, because that figure comes from marketing copy rather than research; * enforce a one-page rule; * treat a font choice, a photo, or an employment gap as a defect. Employment gaps, writing style, and length are reported as **unscored tips**. They never move the score. ## Reading the report The report has three parts. **A score from 0 to 100.** It is the weighted result of five categories: readability, layout, sections, contact details, and dates. A blocking problem puts a hard ceiling on it: a file with no text layer cannot score well just because its margins are tidy. **A category breakdown.** Each category expands into the checks that ran, what failed, and what to do about it. Every finding cites evidence from your file: the text that triggered it and the page it sits on. **A denominator you can trust.** The report says "X of Y applicable checks passed" and states how many were skipped. A check is skipped when it cannot honestly run. Section detection only works on resumes written in English, for instance, and some checks need page contents that a very large file may not yield in time. ## Checking from the builder The **ATS Check** section in the builder's right sidebar has two tiers: These run as you type, against your resume data rather than a file. They catch missing dates, malformed links, prose in a narrow sidebar, and similar problems before you export anything. Click **Run deep check** to render your current resume to a PDF in your browser and run the full file check against those bytes, which is the same file a recruiter would receive. ## Adding an AI review Once a report exists, you can ask an AI provider to review the **writing**: weak phrasing, bullets that describe duties rather than outcomes, and where a rewrite would land better. The AI review needs your own tested AI provider in **Dashboard → Settings → Integrations**. See [Using Artificial Intelligence](/guides/using-ai). It sends the text already extracted from your PDF, plus the job description if you pasted one, to the provider you pick. The PDF file itself is never uploaded. The AI review returns no score. The deterministic report owns the only number in this feature, and an AI-adjusted score would make it mean less. Treat the review as a second opinion on your writing, not a verdict. # Using the builder dock Source: https://docs.rxresu.me/guides/using-the-builder-dock Use the builder dock for undo and redo, zoom controls, page stacking, opening the AI Agent, and copying the public resume URL. The builder dock is the floating toolbar at the bottom of the resume builder. It holds undo and redo, preview controls, the AI Agent workspace, and the resume's public URL, so you can reach them without leaving the canvas. Resume builder showing the floating dock with undo, redo, zoom controls, page stacking toggle, AI agent and copy URL buttons ## Undo and redo The dock starts with **Undo** and **Redo** buttons. They apply to every change in the builder: typing, drag-and-drop, template switches, layout changes, and AI edits. You can also use keyboard shortcuts: | Shortcut | Action | | ------------------ | --------------------------- | | `Cmd/Ctrl+Z` | Undo the last change | | `Cmd/Ctrl+Shift+Z` | Redo the last undone change | Rapid typing collapses into a single undo step, so one undo removes a phrase rather than one letter. When your cursor is inside a text field, the shortcut falls back to your browser's native input undo. Click outside the field, or use the dock buttons, to undo builder-wide changes. For longer-range recovery, such as jumping back to a template switch, an import, or an AI edit, see [Undoing changes and version history](/guides/undoing-changes-and-version-history). ## Zoom controls Use the zoom controls to adjust the preview. | Control | What it does | | ------------------ | ------------------------------------------------------------------------------------- | | **Zoom out** | Decreases the preview zoom. | | **Zoom level (%)** | Shows the current zoom. Opens a menu with **Actual size (100%)** and **Fit to view**. | | **Zoom in** | Increases the preview zoom. | Press `Cmd/Ctrl+0` to reset the zoom to fit. Zoom only affects the editor preview. It does not change the exported PDF, DOCX, or JSON file. ## Toggle page stacking Use the page-stacking button to switch between stacked pages (vertical) and side-by-side pages (horizontal). This only affects the editor preview. ## Open the AI Agent Click the chat button to open the **AI Agent** workspace in a new page, pre-scoped to the current resume. The agent suits larger, standalone conversations that create their own draft. For chatting about the open resume without leaving the builder, use the AI assistant in the builder header instead. See [Using AI in the builder](/guides/using-ai-in-the-builder). ## Copy the public URL Click **Copy URL** to copy the resume's public URL. The URL is based on your username and the resume slug: ```txt theme={null} https://rxresu.me/{username}/{slug} ``` Copying the URL does not make the resume public by itself. To allow visitors to open the link, enable public access in the **Sharing** section of the right sidebar. ## Downloading your resume Downloads are no longer on the dock. Use the primary **Download PDF** button in the builder header, or open the dropdown next to it for **DOCX**, **JSON**, and **Print**. See [Exporting your resume](/guides/exporting-your-resume). # Using the MCP server Source: https://docs.rxresu.me/guides/using-the-mcp-server Connect Reactive Resume to AI tools like Claude Desktop, Cursor, and Codex through the Model Context Protocol to edit and manage resumes via chat. The Reactive Resume MCP server lets you manage your resumes and job applications from any MCP-compatible AI tool: Claude Desktop, Cursor, Codex, and others. It connects to the Reactive Resume API and exposes tools for resume editing, Application Tracker workflows, and AI-assisted job application tasks, driven by natural language. ## What is MCP? The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) is a standard that lets LLM-powered tools connect to external services. Instead of being limited to the built-in chat UI, you can use any MCP client to interact with your resumes. ## Prerequisites Reactive Resume MCP supports two authentication methods: * **OAuth2 (recommended):** best user experience for clients that support MCP OAuth. * **API key (fallback):** works in all clients that can send custom headers. Use OAuth2 whenever your MCP client supports it. Use API key only when OAuth is unavailable in that client. Head over to [https://rxresu.me](https://rxresu.me) (or your self-hosted instance), sign in, and navigate to **Settings → API Keys**. Click **Create a new API key**, give it a name, and copy the secret. It is shown only once. For the full walkthrough, see [Using the API](/guides/using-the-api). ## Configuration There are two transport options, and each can use either OAuth2 or API key depending on your client capabilities. ### Method 1: Streamable HTTP (recommended) If your client supports the `url` field (e.g. **Cursor**, **Codex**, Claude custom connectors), use this. #### Option A: OAuth2 (recommended) Most OAuth-capable clients only need the MCP URL: ```json theme={null} { "mcpServers": { "reactive-resume": { "url": "https://rxresu.me/mcp" } } } ``` Then connect/sign in from the client UI (or with the client's OAuth login command). #### Option B: API key (fallback) If OAuth is not supported in your client, send `x-api-key`: ```json theme={null} { "mcpServers": { "reactive-resume": { "url": "https://rxresu.me/mcp", "headers": { "x-api-key": "your-api-key" } } } } ``` ### Method 2: mcp-remote If your client only supports `command` / `args` (for example, local-only Claude Desktop config), use [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) as a bridge. This requires [Node.js](https://nodejs.org) **20 or later**. `mcp-remote` is most commonly used with API keys: ```json theme={null} { "mcpServers": { "reactive-resume": { "command": "npx", "args": ["mcp-remote", "https://rxresu.me/mcp", "--header", "x-api-key:your-api-key"] } } } ``` Replace `your-api-key` with the API key you created in the prerequisites step. ### Where to put the config | Client | Config file | | ----------------- | ------------------------------------------------------------------------------------------------ | | Cursor | `.cursor/mcp.json` in your project or home directory | | Claude Desktop | `claude_desktop_config.json` ([docs](https://modelcontextprotocol.io/quickstart/user)) | | Codex | `~/.codex/config.toml` or `.codex/config.toml` ([docs](https://developers.openai.com/codex/mcp)) | | Other MCP clients | Refer to the client's documentation | ## Authentication details (how Reactive Resume MCP works) Reactive Resume MCP accepts authentication in this order: 1. **Bearer token (OAuth2 access token)** via `Authorization: Bearer ` 2. **API key fallback** via `x-api-key: ` If neither is valid, the MCP endpoint responds with `401` and advertises OAuth metadata using: * `WWW-Authenticate: Bearer resource_metadata="/.well-known/oauth-protected-resource"` OAuth-capable MCP clients use this to discover and complete the OAuth flow automatically. ### OAuth2 flow used by this server Reactive Resume is configured as an OAuth authorization server for MCP clients: * The MCP endpoint is `https://rxresu.me/mcp`. * OAuth discovery metadata is exposed under `/.well-known/*` endpoints. * The login/authorization route is `/api/auth/oauth`. * If the user is not signed in, `/api/auth/oauth` redirects to `/auth/login`, then resumes OAuth. * If the user is signed in, `/api/auth/oauth` uses the OAuth provider to validate the signed request, registered redirect URI, scopes, resource grants, and PKCE before issuing an authorization code, and redirects back to the client. * PKCE parameters (`code_challenge`, `code_challenge_method`) are preserved in the authorization flow. ## Popular client setup ### Cursor **OAuth2 (recommended):** ```json theme={null} { "mcpServers": { "reactive-resume": { "url": "https://rxresu.me/mcp" } } } ``` **API key fallback:** ```json theme={null} { "mcpServers": { "reactive-resume": { "url": "https://rxresu.me/mcp", "headers": { "x-api-key": "your-api-key" } } } } ``` ### Codex (CLI / IDE extension) Add server: ```bash theme={null} codex mcp add reactive-resume --url https://rxresu.me/mcp ``` Then sign in with OAuth: ```bash theme={null} codex mcp login reactive-resume ``` API key fallback (`config.toml`): ```toml theme={null} [mcp_servers."reactive-resume"] url = "https://rxresu.me/mcp" http_headers = { "x-api-key" = "your-api-key" } ``` ### Claude (web app custom connector) Add `https://rxresu.me/mcp` as a custom remote MCP connector, then connect with OAuth in Claude's connector UI. ### Claude Desktop (local config file) Use `mcp-remote` bridge with API key (example shown above in **Method 2**). ## External references * [Cursor MCP docs](https://cursor.sh/docs/mcp) * [MCP quickstart for users (Claude Desktop example)](https://modelcontextprotocol.io/quickstart/user) * [OpenAI Codex MCP docs](https://developers.openai.com/codex/mcp) * [Claude custom connectors (remote MCP)](https://claude.com/docs/connectors/custom/remote-mcp) * [MCP Authorization spec](https://modelcontextprotocol.io/specification/latest/basic/authorization) ## Self-hosting If you're running a self-hosted Reactive Resume instance, replace `https://rxresu.me/mcp` with your instance URL: ```json theme={null} { "url": "https://resume.example.com/mcp", "headers": { "x-api-key": "your-api-key" } } ``` ### Reconnecting after the OAuth provider upgrade Self-hosted instances automatically apply the additive OAuth schema migration at startup. This preserves existing client and token records and adds the provider's resource and client-resource tables. Clients registered before OAuth provider 1.7 do not have per-resource grants. Remove the old connection from your MCP client and add it again so it dynamically registers a new client, then sign in again. Refreshing an existing token does not create these grants. New registrations receive only the resources configured for this instance; existing clients are not automatically granted access. ## Available tools Tool names use canonical unprefixed `snake_case` names. | Tool | Description | | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `list_resumes` | List all resumes with IDs, names, tags, and status. Supports filtering by tags and sorting by last updated, creation date, or name | | `list_resume_tags` | List every distinct tag in use across your resumes (sorted) | | `read_resume` | Get the full data of a specific resume by ID | | `download_resume_pdf` | Create a 10-minute authenticated PDF download URL. Defaults to the resume; set `target: "cover-letter"` for its visible cover letter | | `create_resume` | Create a new, empty resume with a name and slug. Optionally pre-fill with sample data | | `import_resume` | Create a resume from a full ResumeData JSON export (random name/slug). Large files may exceed client limits | | `duplicate_resume` | Create a copy of an existing resume with a new name and slug | | `apply_resume_patch` | Apply JSON Patch (RFC 6902) operations to modify a resume's data | | `update_resume` | Update metadata only: name, slug, tags, `isPublic`. Returns canonical share URL; passwords are not managed via MCP | | `delete_resume` | Permanently delete a resume and all associated files. **Irreversible** | | `lock_resume` | Lock a resume to prevent edits, patches, and deletion | | `unlock_resume` | Unlock a previously locked resume to re-enable editing | | `get_resume_statistics` | Get view and download statistics for a resume | | `list_applications` | List tracked job applications. Supports stage, tag, and archived filters | | `read_application` | Read one full application record with contacts, follow-up details, documents, and timeline | | `list_application_tags` | List every distinct tag used across applications | | `get_application_stats` | Get aggregate application counts by stage and source | | `create_application` | Create a tracked job application | | `update_application` | Update fields, move stage, archive/unarchive, edit contacts/follow-ups/tags, or link a resume | | `add_application_note` | Append a note to an application's activity timeline | | `delete_application` | Permanently delete one application and its owned uploaded documents | | `bulk_update_applications` | Move, archive/unarchive, or add tags to multiple applications | | `bulk_delete_applications` | Permanently delete multiple applications | | `import_applications` | Bulk-create parsed application rows, up to 500 items | | `attach_application_document` | Attach a sent resume or cover-letter PDF from base64-encoded PDF bytes | | `remove_application_document` | Remove a sent resume or cover-letter PDF | | `autofill_application_from_job` | Use AI to extract job details from a URL or pasted job description | | `score_application_match` | Score the linked resume against the application job description | | `tailor_resume_for_application` | Create and link a tailored resume copy for an application | | `draft_application_message` | Draft a cover letter or recruiter follow-up from application and resume context | ### Breaking change (tool names) Older clients may refer to prefixed or dot-separated names. Those names are no longer registered; update automations and saved prompts to the canonical names above. ## Available resources Resources follow MCP conventions: **static** items appear in `resources/list`; **parameterized** access is declared in `resources/templates/list` and read via `resources/read` once you know the ID. | Discovery | What you get | | -------------------------- | -------------------------------------------------------------------------------------------- | | `resources/list` | Static resources only: currently **`resume://_meta/schema`** (ResumeData JSON Schema) | | `resources/templates/list` | **`resume://{id}`**: template for reading full resume JSON by ID (not enumerated per resume) | | `list_resumes` (tool) | **Primary way to discover resume IDs**; resumes are not listed as separate MCP resources | | URI | Description | | ----------------------- | ---------------------------------------------------------------------- | | `resume://_meta/schema` | ResumeData JSON Schema; use for valid JSON Patch paths and value types | | `resume://{id}` | Full resume data as JSON; use an ID from `list_resumes` | ### Breaking change (schema URI) The schema resource was previously `resume://schema`. It is now **`resume://_meta/schema`**. Update any saved prompts, automations, or client configs that referenced the old URI. ### Static server card (`/.well-known/mcp/server-card.json`) `GET /.well-known/mcp/server-card.json` returns a JSON document ([SEP-1649](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1649)) with `serverInfo`, optional authentication metadata, and summaries of tools, resources, resource templates, and prompts. It is generated to match the live MCP server, and a client that cannot run a full capability scan against `/mcp/` can use it for discovery. ## Available prompts Prompts are pre-built workflows that give the AI structured instructions and context. Each prompt embeds the resume data and the schema resource (`resume://_meta/schema`) automatically. | Prompt | Description | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | `build_resume` | Guide you step-by-step through building a resume from scratch: basics, summary, experience, education, skills, and design | | `improve_resume` | Review your resume and suggest concrete improvements to wording, impact, metrics, and structure | | `review_resume` | Get a structured, professional critique with a scorecard (1–10 across seven dimensions) and prioritized recommendations. **Read-only**; no changes are made | ## Usage examples Once your MCP client is connected, you can work with your resumes in natural language: ### Browsing * "List my resumes" * "Show me my resume named 'Software Engineer'" * "What skills are listed on my resume?" * "Show me the stats for my resume" ### Tracking applications * "Create an application for Senior Frontend Engineer at Acme, stage saved, source LinkedIn." * "List my archived applications tagged remote." * "Move my Acme application to interview and add a note that the technical screen is next Tuesday." * "Attach this resume PDF to the Acme application." * "Score the resume linked to this application against the job description." * "Create a tailored resume copy for this application." * "Draft a follow-up message for the recruiter." For a complete workflow and prompt library, see [Managing applications with MCP](/guides/managing-applications-with-mcp). ### Creating and managing * "Create a new resume called 'Frontend Engineer 2026'" * "Import this exported ResumeData JSON as a new resume" * "What tags do I use across my resumes?" * "Duplicate my 'Software Engineer' resume for a product manager role" * "Make my resume public and give me the share link" * "Lock my finalized resume so it can't be accidentally edited" * "Delete my old draft resume" * "Download a PDF of my Software Engineer resume" * "Download the visible cover letter from my Software Engineer resume as a PDF" ### Editing * "Update my name to Jane Doe" * "Change my headline to Senior Software Engineer" * "Add TypeScript to my skills with an Advanced proficiency level" * "Add a new experience entry for my role as Staff Engineer at Acme Corp from Jan 2024 to Present" * "Remove the third item from my skills section" ### Styling * "Change the template to bronzor" * "Set the primary color to blue" * "Hide the interests section" ### Using prompts * "Help me build my resume from scratch" (uses `build_resume`) * "Review my resume and give me a score" (uses `review_resume`) * "Improve the wording on my resume" (uses `improve_resume`) The AI reads your current resume with `read_resume` before making changes with `apply_resume_patch`, so it targets the correct JSON paths. Use `update_resume` for name, slug, tags, and public visibility, not for section content. ## Troubleshooting | Issue | Solution | | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | | "Unauthorized" with no login prompt | Your client may not support MCP OAuth discovery. Use API key mode (`x-api-key`) | | OAuth login opens but fails redirect/callback | Confirm your client's MCP OAuth callback settings and retry the connection | | "API error (401)" | Your API key is invalid or expired. Create a new one in **Settings → API Keys** | | "API error (404)" | The resume ID doesn't exist. Use `list_resumes` to find valid IDs | | "API error (403)" | The resume is locked. Unlock it in the Reactive Resume dashboard | | Connection refused | Check that the URL is correct and the instance is running | | "ReferenceError: File is not defined" when using `mcp-remote` | You're running Node.js 18. `mcp-remote` requires **Node.js 20 or later**; upgrade with `nvm use 20` or `nvm alias default 20` | | "Application documents must be PDF files" | `attach_application_document` only accepts `contentType: "application/pdf"` and base64-encoded PDF bytes | # Using the patch API Source: https://docs.rxresu.me/guides/using-the-patch-api Partially update a Reactive Resume with JSON Patch (RFC 6902) operations to add, remove, replace, and move fields without sending the full document. The Patch API lets you make small, targeted changes to your resume without sending the entire data object. Instead of replacing the whole resume with a `PUT`, you send a list of **JSON Patch** operations that describe exactly what to change. This is based on the [JSON Patch (RFC 6902)](https://datatracker.ietf.org/doc/html/rfc6902) standard. ## When to use PATCH vs PUT | Use case | Method | | -------------------------------------------- | --------- | | Update a single field (e.g., name, headline) | **PATCH** | | Add or remove an item in a section | **PATCH** | | Change template, colors, or fonts | **PATCH** | | Replace the entire resume data at once | **PUT** | The PATCH endpoint only modifies the resume `data` (the JSONB column). To update top-level resume properties like `name`, `slug`, `tags`, or `isPublic`, use the existing `PUT /resume/{id}` endpoint. ## Authentication All requests require your API key in the `x-api-key` header. See [Using the API](/guides/using-the-api) for how to create one. If you're self-hosting, replace `https://rxresu.me` with your instance URL. The API is served under `/api/openapi`. ## Endpoint ``` PATCH /api/openapi/resume/{id} ``` ### Request body The resume ID is taken from the URL path, so the request body only requires the `operations` array: ```json theme={null} { "operations": [{ "op": "replace", "path": "/basics/name", "value": "Jane Doe" }] } ``` Each operation is an object with the following properties: | Property | Required | Description | | -------- | ---------------------------- | ------------------------------------------------------------------------------- | | `op` | Yes | The operation to perform: `add`, `remove`, `replace`, `move`, `copy`, or `test` | | `path` | Yes | A JSON Pointer (RFC 6901) to the target location in the resume data | | `value` | For `add`, `replace`, `test` | The value to use for the operation | | `from` | For `move`, `copy` | A JSON Pointer to the source location | ## Examples ### Replace a basic field Update the resume holder's name and headline: ```bash theme={null} curl -X PATCH "https://rxresu.me/api/openapi/resume/YOUR_RESUME_ID" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "replace", "path": "/basics/name", "value": "Jane Doe" }, { "op": "replace", "path": "/basics/headline", "value": "Senior Software Engineer" } ] }' ``` ### Add an experience entry Append a new item to the experience section: ```bash theme={null} curl -X PATCH "https://rxresu.me/api/openapi/resume/YOUR_RESUME_ID" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "add", "path": "/sections/experience/items/-", "value": { "id": "a1b2c3d4-0000-0000-0000-000000000000", "hidden": false, "company": "Acme Corp", "position": "Staff Engineer", "location": "San Francisco, CA", "period": "Jan 2024 - Present", "website": { "url": "https://acme.example.com", "label": "Acme Corp" }, "description": "

Leading the platform team.

" } } ] }' ``` The path `/sections/experience/items/-` uses the special `-` index, which means "append to the end of the array". To insert at a specific position, use a numeric index like `/sections/experience/items/0` for the beginning. ### Remove an item from a section Remove the second skill (index `1`) from the skills section: ```bash theme={null} curl -X PATCH "https://rxresu.me/api/openapi/resume/YOUR_RESUME_ID" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "remove", "path": "/sections/skills/items/1" } ] }' ``` ### Update metadata (template, colors, fonts) Switch the template and update the primary color: ```bash theme={null} curl -X PATCH "https://rxresu.me/api/openapi/resume/YOUR_RESUME_ID" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "replace", "path": "/metadata/template", "value": "bronzor" }, { "op": "replace", "path": "/metadata/design/colors/primary", "value": "rgba(37, 99, 235, 1)" } ] }' ``` ### Test then replace (optimistic concurrency) The `test` operation checks that a value matches before the rest of the patch runs. If the test fails, the whole patch is rejected, which keeps you from overwriting changes made by another client: ```bash theme={null} curl -X PATCH "https://rxresu.me/api/openapi/resume/YOUR_RESUME_ID" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "test", "path": "/basics/name", "value": "Albert Einstein" }, { "op": "replace", "path": "/basics/name", "value": "Jane Doe" } ] }' ``` If `/basics/name` is not `"Albert Einstein"` at the time of the request, the entire patch will fail with a `400` error and no changes will be applied. ### Move an item within a section Move the first experience item to the third position: ```bash theme={null} curl -X PATCH "https://rxresu.me/api/openapi/resume/YOUR_RESUME_ID" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "move", "from": "/sections/experience/items/0", "path": "/sections/experience/items/2" } ] }' ``` ## Error handling | Status | Error Code | Description | | ------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `400` | `INVALID_PATCH_OPERATIONS` | The operations are structurally invalid, target a non-existent path, or produce resume data that fails schema validation. | | `401` | `UNAUTHORIZED` | Missing or invalid API key. | | `404` | `NOT_FOUND` | The resume does not exist or does not belong to the authenticated user. | | `403` | `RESUME_LOCKED` | The resume is locked and cannot be modified. Unlock it first. | All operations in a single request are applied atomically. If any operation fails (including a `test`), none of the operations are applied. ## Tips * Fetch first, then patch. Use `GET /resume/{id}` to inspect the current structure before writing your operations, so you target the correct paths and array indices. * Use `test` for safety. When you expect a field to hold a specific value, combine `test` + `replace` so you don't overwrite a concurrent change. * Batch related changes. You can send multiple operations in one request. They are applied in order, so a later operation can depend on an earlier one. * The `-` index appends. When adding items to arrays, use `-` as the index (e.g., `/sections/skills/items/-`) to append to the end. # License Source: https://docs.rxresu.me/legal/license Read the MIT license that covers Reactive Resume, an open-source resume builder you can freely use, modify, self-host, and redistribute. ## Open-source license (MIT) Reactive Resume is open-source software. The project is published under the **MIT License**, which allows you to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software. If you are running a modified/self-hosted instance, you may have additional notices or third-party licenses that apply (for example, fonts, icons, or other bundled assets). For the upstream repository, see: [amruthpillai/reactive-resume](https://github.com/amruthpillai/reactive-resume) *** ## MIT License text MIT License Copyright (c) 2023 Amruth Pillai Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # Privacy Policy Source: https://docs.rxresu.me/legal/privacy-policy How the hosted Reactive Resume service handles your personal data, account information, uploaded files, cookies, analytics, and PDF printing. ## Overview This Privacy Policy explains how **Reactive Resume** (the "Service") collects, uses, stores, and shares information when you use it. Reactive Resume is open-source and can be operated in different ways (for example, by the official hosted service, or by an organization/self-hosted deployment). The specific data controller for your use depends on who operates the instance you are using. * **Service Operator**: Amruth Pillai * **Contact**: [hello@amruthpillai.com](mailto:hello@amruthpillai.com) * **Service URL**: [https://rxresu.me](https://rxresu.me) * **Effective date**: 2023-01-01 If you are self-hosting, **you** are the Service Operator and responsible for compliance (including configuring email delivery, storage, and logging appropriately). **Note for self-hosted deployments:** If you are using the official hosted service at rxresu.me, the project's published support contact is [hello@amruthpillai.com](mailto:hello@amruthpillai.com). Replace the placeholders above with the correct operator details for your deployment if you are self-hosting. *** ## What the Service does Reactive Resume is a resume builder that lets you: * Create and edit resumes in a browser-based builder * Store resumes in an account, optionally mark them public, and share them via a link * Export/print resumes to PDF and generate preview screenshots * Upload files such as profile pictures (and other assets used in a resume) * Optionally configure AI features (e.g., using OpenAI/Gemini/Anthropic) from your own device *** ## Information we collect ### Account information When you create an account or sign in, the Service stores: * **Identity and profile**: name, email address, username/display username, optional profile image * **Authentication state**: whether email is verified; whether two-factor authentication is enabled If you use social sign-in (e.g., Google, GitHub, or a custom OAuth provider), the Service stores identifiers and tokens needed to link and maintain that login. ### Authentication and security data To keep your account secure and keep you signed in, the Service stores: * **Session data**: session token, session expiry, and (if provided) IP address and user agent * **Verification data**: values used for email verification, password reset, or email change flows * **Two-factor authentication**: a 2FA secret and backup codes (if you enable 2FA) * **Passkeys** (if you use them): public key, credential ID, device metadata, counters, and related fields The Service Operator may also send **transactional emails** (for example, password reset or email verification). Depending on deployment, these emails may be delivered via an email provider or (in development/testing) the links may be logged to server output. ### Resume content When you create or import a resume, the Service stores the resume data you provide, which may include personal data such as: * Contact details, location, summary * Employment, education, projects, links, and other resume sections * Any other content you add (including rich text) Resumes may also have metadata such as tags, a slug, visibility (public/private), and an optional resume password (if you lock a resume). ### Public resume access and statistics If you publish a resume, other users may access it via its public link. The Service may also maintain simple statistics such as: * View count and download count * Last viewed/downloaded timestamps ### Uploaded files (e.g., profile pictures) If you upload files, the Service stores them either: * On the **local filesystem** of the server (default: under a `data/` directory), or * In **S3-compatible object storage**, if configured by the Service Operator Depending on configuration, uploaded files may be publicly accessible (for example, some S3 configurations may default to public read access for uploaded objects). The Service Operator is responsible for selecting appropriate access controls for uploads. ### API keys created in the Service If the Service Operator enables API key functionality, the Service can store: * API key metadata and rate limit counters * The API key value itself (as stored by the Service) ### Local-only preferences and settings Some settings are stored on your device: * **Cookies**: UI preferences such as `theme` and `locale` * **Local storage**: some client-side state and, if you enable AI features, your **AI provider configuration and API key** may be stored in your browser's local storage These local-only values are stored in your browser and are not necessarily transmitted to the Service Operator unless you choose to use related features. *** ## How we use information We use the information above to: * Provide and operate the Service (account access, resume editing, storage, sharing) * Authenticate users and prevent abuse/fraud (sessions, security logs/metadata) * Generate PDFs and screenshots you request * Maintain basic functionality such as localization and theme preferences * Provide support and respond to user requests (if you contact the Service Operator) *** ## Cookies and similar technologies The Service uses cookies primarily for functionality: * **Authentication cookies**: to keep you signed in * **Preference cookies**: theme (`theme`) and language (`locale`) The Service does not include built-in behavioral advertising or third-party analytics by default. (For example, the authentication layer's built-in telemetry is disabled in this codebase.) *** ## Sharing and third parties We share information only as needed to provide the Service: ### PDF generation (client-side) When you export to PDF, the Service renders the document directly in your browser using `@react-pdf/renderer`. Resume content is processed locally on your device for this purpose and is not sent to a separate rendering service. No third-party "printer" or headless-browser service is involved in the export. ### Storage providers (optional) If configured, uploaded files may be stored in an S3-compatible provider. In that case, the storage provider processes and stores file data on behalf of the Service Operator. ### OAuth providers (optional) If you sign in via OAuth (Google/GitHub/custom), those providers receive authentication requests and return profile information (such as email/name) to the Service, as permitted by your provider settings. ### AI providers (optional, user-supplied) If you enable AI features and provide your own API key, prompts and generated content may be sent to your selected AI provider (OpenAI, Google, Anthropic), according to your use of those features and the provider's policies. *** ## Data retention Retention depends on the Service Operator's configuration and your actions. As a baseline: * Account data and resumes are retained until you delete them (or your account is deleted). * Session and security data may be retained as needed for authentication and security. * Uploaded files are retained until deleted (for example, when you remove a picture or delete a resume/account). * Cached screenshot artifacts may be retained briefly (for example, minutes) for performance. The Service Operator may also retain backups and logs for limited periods. *** ## Security We take reasonable measures to protect data (authentication, access controls, and storage separation). No method of transmission or storage is 100% secure; you should use strong passwords and enable 2FA/passkeys where available. If you are self-hosting, you are responsible for: * Securing your infrastructure, database, and storage buckets * Using HTTPS and secure cookie settings * Configuring access controls for object storage (and avoiding unintended public access) *** ## International transfers If the Service Operator (or its vendors) stores or processes data in other countries, your information may be transferred internationally. The Service Operator is responsible for providing appropriate safeguards where required by law. *** ## Your choices and rights Depending on your location, you may have rights to access, correct, delete, export, or restrict processing of your personal data. You can often exercise these rights directly in the Service (for example, by editing or deleting resumes), or by contacting the Service Operator. *** ## Children's privacy The Service is not intended for children under the age of 13 (or the minimum age required in your jurisdiction). If you believe a child has provided personal data, contact the Service Operator. *** ## Changes to this Policy We may update this Privacy Policy from time to time. Changes will be posted on this page with an updated effective date. *** ## Contact For privacy requests or questions, contact: * **Service Operator**: Amruth Pillai * **Email**: [hello@amruthpillai.com](mailto:hello@amruthpillai.com) # Terms of Service Source: https://docs.rxresu.me/legal/terms-of-service Terms and conditions for using the hosted Reactive Resume service, covering accounts, acceptable use, public resumes, uploads, exports, and liability. ## Agreement These Terms of Service (the "Terms") govern your access to and use of **Reactive Resume** (the "Service"). By using the Service, you agree to these Terms. * **Service Operator**: Amruth Pillai * **Contact**: [hello@amruthpillai.com](mailto:hello@amruthpillai.com) * **Service URL**: [https://rxresu.me](https://rxresu.me) * **Effective date**: 2023-01-01 If you do not agree, do not use the Service. Replace the placeholders above with the correct operator details for your deployment. If you are using the official hosted service at rxresu.me, the project's published support contact is [hello@amruthpillai.com](mailto:hello@amruthpillai.com). *** ## The Service Reactive Resume is a resume builder that allows you to create, store, and share resumes, upload related assets, and export/print resumes (including generating PDFs and screenshots). *** ## Eligibility You must be legally able to form a contract in your jurisdiction to use the Service. If you are using the Service on behalf of an organization, you represent that you are authorized to bind that organization to these Terms. *** ## Accounts and security * **Account information**: You agree to provide accurate information and keep it up to date. * **Credentials**: You are responsible for maintaining the confidentiality of your login credentials and for activities that occur under your account. * **Security features**: Where available, you should enable 2FA or passkeys to improve account security. The Service Operator may suspend or terminate accounts to protect the Service, other users, or to comply with legal obligations. *** ## Your Content ### What you provide "Content" includes the resume data you enter or import (text, links, personal details, etc.) and any files you upload (e.g., profile pictures). ### Ownership You retain ownership of your Content. ### License to operate the Service You grant the Service Operator a limited license to host, store, process, and display your Content **only as necessary** to provide the Service (for example, to render your resume in the builder, generate PDFs, serve uploaded images, or show a public resume page you publish). ### Public resumes and sharing If you set a resume as **public** or share a link, you understand that anyone with access to that link may view (and potentially copy) the content you make available. You are responsible for what you choose to publish. If you password-protect a resume, you are responsible for controlling distribution of that password. *** ## Acceptable use You agree not to: * Use the Service for unlawful, harmful, or abusive activities * Attempt to gain unauthorized access to accounts, systems, or data * Upload malware, exploit code, or content designed to disrupt the Service * Use automated means to scrape, overload, or interfere with the Service without permission * Infringe intellectual property, privacy, or other rights of others The Service Operator may remove Content or restrict access if needed to enforce these Terms or comply with law. *** ## Uploads, storage, and delivery Uploaded files may be stored on the Service Operator's infrastructure and may be served back to you (and, if your resume is public, to others). Depending on configuration, storage may be local filesystem storage or S3-compatible object storage. You represent that you have the rights necessary to upload and use any files and that doing so does not violate any law or third-party rights. *** ## Exports (PDF) When you request a PDF export, the Service renders the document in your own browser using `@react-pdf/renderer`. Your resume content is processed locally by the JavaScript running on your device; it is not transmitted to a separate rendering service for the purpose of generating the PDF. *** ## Third-party services (optional) The Service may integrate with third parties depending on configuration and your choices, including: * OAuth providers (e.g., Google/GitHub/custom OAuth) for sign-in * Storage providers (S3-compatible) * AI providers (OpenAI, Google, Anthropic) if you enable AI features and provide your own API key Your use of third-party services may be subject to their own terms and policies. The Service Operator is not responsible for third-party services outside its control. *** ## API keys (if enabled) If the Service allows you to create API keys: * You are responsible for keeping API keys secure and rotating/revoking them if compromised. * The Service Operator may enforce rate limits, quotas, and permissions. * Misuse of API keys may result in suspension or termination. *** ## Intellectual property and open source Reactive Resume is open-source software licensed under the **MIT License**. These Terms govern **use of the Service**, not the open-source license for the code. See the docs [License page](/legal/license) for details. *** ## Termination You may stop using the Service at any time. The Service Operator may suspend or terminate your access: * To enforce these Terms * To address security risks or abuse * To comply with legal requirements Upon termination, your ability to access Content may be removed. Retention/deletion of data depends on the Service Operator's policies and legal obligations. *** ## Disclaimers THE SERVICE IS PROVIDED **"AS IS"** AND **"AS AVAILABLE"** WITHOUT WARRANTIES OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. The Service Operator does not guarantee that the Service will be uninterrupted, error-free, or that exports will always succeed. *** ## Limitation of liability TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SERVICE OPERATOR WILL NOT BE LIABLE FOR INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, OR ANY LOSS OF PROFITS, DATA, OR GOODWILL, ARISING OUT OF OR RELATED TO YOUR USE OF (OR INABILITY TO USE) THE SERVICE. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SERVICE OPERATOR'S TOTAL LIABILITY FOR ANY CLAIM ARISING OUT OF OR RELATING TO THE SERVICE WILL NOT EXCEED THE AMOUNT YOU PAID (IF ANY) TO USE THE SERVICE IN THE 12 MONTHS BEFORE THE EVENT GIVING RISE TO THE CLAIM. *** ## Indemnification You agree to defend, indemnify, and hold harmless the Service Operator from and against claims, liabilities, damages, losses, and expenses arising from: * Your Content * Your misuse of the Service * Your violation of these Terms *** ## Changes to these Terms We may update these Terms from time to time. Updated Terms will be posted on this page with a new effective date. Continued use of the Service after changes become effective constitutes acceptance. *** ## Governing law These terms are governed by the laws of the **Federal Republic of Germany**. For matters specifically relating to data protection, you may contact:\ **Berlin Commissioner for Data Protection and Freedom of Information**\ Friedrichstraße 219\ D-10969 Berlin Conflict of laws principles do not apply. *** ## Contact Questions about these Terms can be sent to: * **Service Operator**: Amruth Pillai * **Email**: [hello@amruthpillai.com](mailto:hello@amruthpillai.com) # Self-hosting with Docker Source: https://docs.rxresu.me/self-hosting/docker How to self-host Reactive Resume with Docker (Postgres only), with an environment variable reference and troubleshooting tips. **From v5.1.0 onwards** — PDF generation now runs entirely client-side via `@react-pdf/renderer`. New deployments no longer require Browserless, Chromium, or any external print service as a dependency. The `PRINTER_*` and `BROWSERLESS_*` environment variables are no longer read and can be removed from your `.env`. ## Overview Reactive Resume can be self-hosted with Docker. These are the services you'll need: The official image runs one application container that serves both the web app and API. PostgreSQL must run as a separate service and the app connects to it through `DATABASE_URL`; no all-in-one image with an embedded database is planned. Follow the [Docker Compose quickstart](#quickstart-using-docker-compose) below for the supported setup. Stores accounts, resumes, and application data. SMTP for verification emails, password reset, etc. If not configured, emails are logged to the server console. Use S3-compatible storage, or local persistent storage via /app/data. You can pull the latest app image from: * Docker Hub: `amruthpillai/reactive-resume:latest` * GitHub Container Registry: `ghcr.io/amruthpillai/reactive-resume:latest` ## Minimum requirements Docker Engine + Docker Compose plugin (or Docker Desktop). 1 vCPU / 1 GB RAM minimum (2 GB recommended if Postgres runs on the same host). Enough for Postgres + uploads (start with 10-20 GB and scale as needed). ## Smallest supported setup 1. Provide a separate, healthy PostgreSQL service. In the example below, its service name is `postgres`. 2. Put `APP_URL`, `DATABASE_URL`, and `AUTH_SECRET` in a private `.env` file. Set the database host in `DATABASE_URL` to a name or address reachable from the app container. 3. If S3 is disabled, mount persistent storage for app uploads at `/app/data`. 4. Attach the `reactive-resume` app service and PostgreSQL service to the intended private container network. Do not expose PostgreSQL to the public internet. 5. Launch the services with the [Docker Compose quickstart](#quickstart-using-docker-compose) below. 6. Wait for PostgreSQL, automatic migrations, and the app health check before opening the UI. The repository's full `compose.yml` also defines optional Redis and S3-compatible storage services. Those services are not required for the core resume workflow; use the two-service example below when you only need the app and PostgreSQL. The repository file is a broader source-build stack and publishes administration ports for local use. Before using it on an internet-facing host, remove those host port mappings, bind them to loopback, or restrict them with a firewall. ## Quickstart using Docker Compose Create a new folder (for example `reactive-resume/`) with: * `compose.yml` * `.env` * a persistent data directory for uploads (for example `./data`) Start by creating a `.env` file next to your `compose.yml`. The Compose example below reads `.env` directly. If you use the repository's `compose.yml` instead, copy its `.env.example` into the same folder. That file supplies defaults before your `.env` overrides are applied. ```bash .env theme={null} # --- Server --- TZ="Etc/UTC" APP_URL="http://localhost:3000" # --- Database (PostgreSQL) --- DATABASE_URL="postgresql://postgres:postgres@postgres:5432/postgres" # --- Authentication --- # Generated using `openssl rand -hex 32` AUTH_SECRET="" # Better Auth dashboard API key (optional) BETTER_AUTH_API_KEY="" # Social Auth (Google, optional) GOOGLE_CLIENT_ID="" GOOGLE_CLIENT_SECRET="" # Social Auth (GitHub, optional) GITHUB_CLIENT_ID="" GITHUB_CLIENT_SECRET="" # Social Auth (LinkedIn, optional) LINKEDIN_CLIENT_ID="" LINKEDIN_CLIENT_SECRET="" # Custom OAuth Provider OAUTH_PROVIDER_NAME="" OAUTH_CLIENT_ID="" OAUTH_CLIENT_SECRET="" # Use EITHER discovery URL (preferred for OIDC-compliant providers): OAUTH_DISCOVERY_URL="" # OR manual URLs (all three required if not using discovery): OAUTH_AUTHORIZATION_URL="" OAUTH_TOKEN_URL="" OAUTH_USER_INFO_URL="" # Custom scopes (space-separated, defaults to "openid profile email") OAUTH_SCOPES="" # --- Email (optional) --- # If all keys are disabled, the app logs the email to be sent to the console instead. SMTP_HOST="" SMTP_PORT="587" SMTP_USER="" SMTP_PASS="" SMTP_FROM="Reactive Resume " SMTP_SECURE="false" # --- Storage (optional) --- # If all S3 keys are disabled, the app uses local filesystem storage instead. # Make sure to mount this directory to a volume or the host filesystem to ensure data integrity. S3_ACCESS_KEY_ID="" S3_SECRET_ACCESS_KEY="" S3_REGION="us-east-1" S3_ENDPOINT="" S3_BUCKET="" # Set to "true" for path-style URLs (https://endpoint/bucket), common with MinIO, SeaweedFS, etc. # Set to "false" for virtual-hosted-style URLs (https://bucket.endpoint), common with AWS S3, Cloudflare R2, etc. S3_FORCE_PATH_STYLE="false" # --- AI features (optional) --- # ENCRYPTION_SECRET is required for saved AI providers. REDIS_URL is also required for the AI Agent workspace. # The rest of Reactive Resume can run without these. REDIS_URL="" # Generated using `openssl rand -hex 32` ENCRYPTION_SECRET="" # --- Feature Flags --- FLAG_DISABLE_SIGNUPS="false" FLAG_DISABLE_EMAIL_AUTH="false" FLAG_DISABLE_IMAGE_PROCESSING="false" FLAG_DISABLE_API_RATE_LIMIT="false" # Allows any parseable dynamic OAuth redirect URI. Keep false unless this is a trusted self-hosted deployment. FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI="false" # Allows unsafe/private/non-public AI provider base URLs. Keep false unless this is a trusted self-hosted deployment. FLAG_ALLOW_UNSAFE_AI_BASE_URL="false" ``` Generate a strong secret and paste it into `AUTH_SECRET`. ```bash Linux/macOS theme={null} openssl rand -hex 32 ``` ```bash Linux/macOS (alternative) theme={null} head -c 32 /dev/urandom | hexdump -v -e '/1 "%02x"' ``` ```powershell Windows theme={null} [byte[]]$bytes = New-Object byte[] 32; (New-Object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($bytes); $bytes | ForEach-Object { "{0:x2}" -f $_ } | Out-String -Stream | ForEach-Object { $_.Trim() } | Write-Host -NoNewline ``` This setup runs Postgres and Reactive Resume on a private Docker network. ```yaml compose.yml theme={null} services: postgres: image: postgres:17 restart: unless-stopped environment: POSTGRES_DB: postgres POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres volumes: - postgres_data:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"] interval: 10s timeout: 5s retries: 10 reactive-resume: image: amruthpillai/reactive-resume:latest # image: ghcr.io/amruthpillai/reactive-resume:latest restart: unless-stopped ports: - "3000:3000" env_file: - .env volumes: # Used when S3 is not configured; keeps uploads persistent - ./data:/app/data depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then((r) => { if (!r.ok) process.exit(1); }).catch(() => process.exit(1));"] interval: 30s timeout: 10s retries: 3 volumes: postgres_data: ``` Prefer pulling from Docker Hub? Keep amruthpillai/reactive-resume:latest. Prefer GHCR? Swap it to ghcr.io/amruthpillai/reactive-resume:latest. In Docker, the Reactive Resume server listens on PORT and serves both the API and the built web app. The default image uses PORT=3000, so the example maps 3000:3000. If you change PORT, update the container-side port mapping and health check to match. ```bash theme={null} docker compose up -d ``` ```bash theme={null} docker compose ps ``` ```bash theme={null} docker compose logs -f reactive-resume ``` Reactive Resume should now be available at your `APP_URL` (for the example above: `http://localhost:3000`). ## Unraid and other homelab platforms Use your platform's generic container configuration to create two separately managed containers: one for Reactive Resume and one for PostgreSQL. No official Unraid Community Applications template is provided. * Use the official `amruthpillai/reactive-resume:latest` or `ghcr.io/amruthpillai/reactive-resume:latest` image for the app container. * Map the app's container port `3000` to the host port you want to use. * Connect both containers to a private container network. Set the host in `DATABASE_URL` to the PostgreSQL container or service name reachable on that network. * Set `APP_URL`, `DATABASE_URL`, and `AUTH_SECRET` as private environment variables. * When S3 is disabled, map persistent app upload storage to `/app/data`. * Give PostgreSQL its own persistent data volume and manage it independently from the app container. `localhost` inside the Reactive Resume container refers to that app container. It cannot reach a separate PostgreSQL container. Use the PostgreSQL container or service name on the private network instead. After starting both containers, wait for PostgreSQL to become healthy and check the app logs while automatic migrations run. Open the UI only after the app health check succeeds. ## How startup works (database migrations) On every start, the server automatically runs database migrations before serving traffic. If migrations fail (usually due to a DB connection issue), the container will exit with an error. ## Environment variables
  • APP\_URL
  • DATABASE\_URL
  • AUTH\_SECRET
  • SMTP (SMTP\_\*)
  • Social auth (GOOGLE\_\*, GITHUB\_\*, LINKEDIN\_\*, OAUTH\_\*)
  • S3 storage (S3\_\*)
  • AI providers and AI Agent workspace (ENCRYPTION\_SECRET, REDIS\_URL)
  • Feature flags (FLAG\_\*)
* **`TZ`**: Sets the container timezone (affects logs and server-side timestamps). Recommended: `Etc/UTC`. * **`APP_URL`**: Canonical/public URL for your instance (used for absolute URLs, redirects, and auth flows). If behind a reverse proxy, set this to your public HTTPS URL (for example, `https://resume.example.com`). * **`PORT`**: Port the production Docker container listens on. Defaults to `3000` in the official image. If you change it, update your Compose port mapping and health check from `3000` to the new container port. * **`SERVER_PORT`**: Used only for local development when the Vite web app and Hono server run as separate processes. It is ignored by the production Docker image. * **`DATABASE_URL`**: Postgres connection string in the format `postgresql://USER:PASSWORD@HOST:PORT/DATABASE`. - In Docker Compose, set `HOST` to the Postgres service name (e.g. `postgres`), not `localhost`. - If your password contains special characters (`@`, `#`, `:`), URL-encode it. - For managed Postgres, add provider-specific params (for example `?sslmode=require`) when needed. **`AUTH_SECRET`**: Secret used to secure authentication. Changing it invalidates existing sessions. Generate with: ```bash theme={null} openssl rand -hex 32 ``` **`GOOGLE_CLIENT_ID`** / **`GOOGLE_CLIENT_SECRET`** (optional): Enables Google sign-in. **`GITHUB_CLIENT_ID`** / **`GITHUB_CLIENT_SECRET`** (optional): Enables GitHub sign-in. **`LINKEDIN_CLIENT_ID`** / **`LINKEDIN_CLIENT_SECRET`** (optional): Enables LinkedIn sign-in. **`BETTER_AUTH_API_KEY`** (optional): Enables Better Auth dashboard integrations. **Custom OAuth provider** (optional): * **`OAUTH_PROVIDER_NAME`**: Display name in the UI * **`OAUTH_CLIENT_ID`** / **`OAUTH_CLIENT_SECRET`**: Required for any custom OAuth provider * **`OAUTH_SCOPES`**: Space-separated scopes (defaults to `openid profile email`) Configure endpoints using **one** of these methods: * **Option A (OIDC Discovery, preferred)**: Set `OAUTH_DISCOVERY_URL` to your provider's `.well-known/openid-configuration` URL * **Option B (manual URLs)**: Set all three: `OAUTH_AUTHORIZATION_URL`, `OAUTH_TOKEN_URL`, and `OAUTH_USER_INFO_URL` If SMTP is not configured, the app logs emails to the server console instead of sending them. * Email delivery is enabled only when **all** of `SMTP_HOST`, `SMTP_USER`, `SMTP_PASS`, and `SMTP_FROM` are set. * **`SMTP_HOST`**: SMTP host (if empty, email sending is disabled). * **`SMTP_PORT`**: Defaults to `587` in the app. * **`SMTP_USER`** / **`SMTP_PASS`**: SMTP credentials. * **`SMTP_FROM`**: Default from address (for example, `Reactive Resume `). * **`SMTP_SECURE`**: `"true"` or `"false"` (string). Match your provider settings. * **Default (local)**: If all `S3_*` values are empty, uploads are stored under `/app/data` in the official image. * Mount local uploads to persistent storage (for example `./data:/app/data`) or uploads can be lost on container recreation. * **`LOCAL_STORAGE_PATH`** (optional): Overrides the local data directory. Defaults to `/app/data` in the official Docker image and `/data` in development. The container validates this path is writable at startup and refuses to start otherwise. * **Rootless Docker**: `/app/data` remains the container path. Prefer the named volume from the example Compose file, or make sure a bind-mounted host directory is writable by the container's `node` user mapping. * **S3/S3-compatible**: Configure `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `S3_REGION`, `S3_ENDPOINT`, and `S3_BUCKET`. * **Agent attachments/private objects**: The AI Agent workspace requires S3-compatible storage for private objects. Local storage rejects private objects. * **`S3_FORCE_PATH_STYLE`** controls bucket addressing (defaults to `"false"`): * `"true"` for path-style URLs (`https://endpoint/bucket`) common with MinIO/SeaweedFS. * `"false"` for virtual-hosted-style URLs (`https://bucket.endpoint`) common with AWS S3 / Cloudflare R2. Saved AI provider management is usable only when **`ENCRYPTION_SECRET`** is configured. The AI Agent workspace also requires **`REDIS_URL`**. The rest of Reactive Resume can run without them. * **`REDIS_URL`**: Redis connection string used by the AI Agent workspace. * **`ENCRYPTION_SECRET`**: Secret used to encrypt saved AI provider credentials. Generate with `openssl rand -hex 32`. * Live web research depends on the selected AI provider/model supporting native web search. The app does not run its own URL crawler. If you use the Postgres-only Compose example above and want the AI Agent workspace, add a Redis service or use managed Redis, then set `REDIS_URL`. * **`FLAG_DISABLE_SIGNUPS`**: Disables new signups (web app and server). Useful for private instances. * **`FLAG_DISABLE_EMAIL_AUTH`**: Disables email/password login entirely. Also disables email verification, forgot password, and reset password flows. Users can still sign up via social auth (Google/GitHub/LinkedIn/Custom OAuth), unless FLAG\_DISABLE\_SIGNUPS is also set to true. Useful when only SSO is required. * **`FLAG_DISABLE_IMAGE_PROCESSING`**: Disables image processing. This is useful if you are using a machine with limited resources, like a Raspberry Pi. * **`FLAG_DISABLE_API_RATE_LIMIT`**: Disables API rate limiting for authentication endpoints. Rate limiting is enabled by default in production to prevent abuse. * **`FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI`**: Allows dynamic OAuth client registration to use any parseable redirect URI, including custom schemes, private hosts, and non-loopback `http://` URLs. **Warning: enabling this on a public or multi-tenant deployment can enable phishing or token exfiltration.** Only enable on trusted, self-hosted deployments. * **`FLAG_ALLOW_UNSAFE_AI_BASE_URL`**: Allows AI providers to be configured with unsafe, private, or non-public base URLs, including `http://` and private/loopback addresses (for example, a local Ollama instance at `http://192.168.1.10:11434`). Public HTTPS provider URLs remain the safe default. **Warning: enabling this on a multi-tenant deployment is an SSRF risk.** Only enable on trusted, self-hosted deployments. ## Updating your installation To update an installation created from the image-based quickstart above to the latest version, follow only the numbered steps below. If you use the repository's full `compose.yml`, use the separate source-build path after these steps. 1. **Back up your database and uploads first.** Do this before every update. The database and upload storage are independent resources. Recreating the app container must preserve both the PostgreSQL data volume or managed database and the `/app/data` mount or S3 bucket. 2. **Pull the latest app image.** Leave the PostgreSQL service unchanged. ```bash theme={null} docker compose pull reactive-resume ``` 3. **Recreate only the app container** to run the new image. ```bash theme={null} docker compose up -d --no-deps reactive-resume ``` 4. **Check migration/startup logs** after deploy. ```bash theme={null} docker compose logs -f reactive-resume ``` 5. **(Optional) Remove old, unused Docker images** to free up disk space. ```bash theme={null} docker image prune -f ``` ### Update from the repository Compose file The repository's full `compose.yml` names its build-only app service `reactive_resume`. After confirming its dependencies are healthy, rebuild that service and follow its migration/startup logs with: ```bash theme={null} docker compose up -d --build --no-deps reactive_resume docker compose logs -f reactive_resume ``` Do not run `docker compose pull` for this build-only service. This process updates the app container and automatically runs DB migrations on startup. If migration fails, restore from backup and fix configuration before retrying. Update PostgreSQL separately from the app. Choose a supported, major-pinned PostgreSQL image or select the target version through your managed provider, then follow that image's, host's, or provider's upgrade procedure. Back up the database and verify that the backup can be restored before a major-version upgrade. Pulling a new app image and running app migrations do not upgrade the PostgreSQL server. ## Backups (recommended) Reactive Resume stores data in two places: the PostgreSQL database and file uploads (either local storage or S3). Back up both on a regular schedule. Test restores for both resources. An app container backup alone does not include the separate database or uploads, and recreating the app container must not replace either persistent resource. ### Database backups Your PostgreSQL database holds all user accounts, resumes, and application data. Use `pg_dump` to take periodic backups and store them somewhere secure. Many providers of managed PostgreSQL also offer automated backups that handle scheduling, retention, and restores for you. ### Upload backups If you're using local storage (the `./data` directory), include this directory in your regular backup routine. A simple approach is to use `rsync` or a similar tool to copy the directory to a remote server or cloud storage. If you're using S3-compatible storage, consider enabling versioning on your bucket to protect against accidental deletions. Most S3 providers also support lifecycle rules for automatic cleanup of old versions and cross-region replication for disaster recovery. ## Health checks Reactive Resume exposes a health check endpoint at `/api/health` that verifies the application and its dependencies. It checks **database** and **storage**; if either is unhealthy, the endpoint returns HTTP `503`. ### How it works The Docker Compose configuration includes a health check that periodically calls the `/api/health` endpoint: ```yaml theme={null} healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then((r) => { if (!r.ok) process.exit(1); }).catch(() => process.exit(1));"] interval: 30s timeout: 10s retries: 3 ``` When the health check fails, Docker marks the container as **unhealthy**. This status is visible when running `docker compose ps` or `docker ps`. ### Reverse proxy integration Most reverse proxies (such as **Traefik**, **Caddy**, or **nginx** with upstream health checks) can use Docker's health status to make routing decisions: * **Healthy containers** receive traffic as normal * **Unhealthy containers** are automatically removed from the load balancer pool This is particularly useful in high-availability setups where you have multiple instances of Reactive Resume. If one instance becomes unhealthy (for example, it loses database or storage connectivity), the reverse proxy will stop routing traffic to it until it recovers. If you're using **Traefik**, it automatically respects Docker health checks when using the Docker provider. Unhealthy containers are excluded from routing without any additional configuration. ### Manually checking health To check your instance yourself: ```bash theme={null} # From outside the container curl -f http://localhost:3000/api/health # Check Docker's health status docker compose ps ``` A healthy response returns HTTP 200. If you get a different status code, the JSON response body says what failed. If the connection is refused or times out there is no response to read, so check the container and reverse-proxy logs instead. ## Troubleshooting * **Common cause**: database migrations failed (often a bad `DATABASE_URL`). * **What to do**: Check logs for migration errors and database connectivity details: ```bash theme={null} docker compose logs -f reactive-resume ``` * **Common cause**: `APP_URL` doesn't match the URL you're actually using (especially behind a reverse proxy), or you're serving HTTPS while `APP_URL` is `http://...`. - **Fix**: set `APP_URL` to your canonical public HTTPS URL and restart the container. * **Common cause**: PDFs are now rendered in the browser via `@react-pdf/renderer`, so failures usually come from a blocked download, an extreme browser memory limit, or a custom CSP that strips inline workers. - **Checks**: confirm the browser is up to date, the page hasn't been opened in a restricted iframe, and that no extension is intercepting the download. There is no server-side printer to inspect. * **Common cause**: storage health failed (not only database). - **Fix**: inspect the endpoint response payload and check the `storage` field: [http://127.0.0.1:3000/api/health](http://127.0.0.1:3000/api/health) * **Cause**: local upload storage wasn't mounted to a persistent volume. - **Fix**: add a volume mount like `./data:/app/data` and redeploy. * **Expected behavior**: if SMTP isn't fully configured, the app logs emails to the console. - **Fix**: set `SMTP_HOST`, `SMTP_USER`, `SMTP_PASS`, and `SMTP_FROM`, then verify `SMTP_PORT` and `SMTP_SECURE`. * **Common cause**: redirect URI is not the app origin or a local loopback callback. - **Fix**: use an app-origin or loopback redirect URI, or enable `FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI` only on a trusted self-hosted deployment that needs arbitrary redirect URIs. * **Common cause**: The S3 client is using virtual-hosted-style addressing (prepending the bucket name to the endpoint), but your S3-compatible storage expects path-style addressing. * **Symptom**: Error message like `getaddrinfo ENOTFOUND mybucket.s3-server.com` when your endpoint is `s3-server.com`. * **Fix**: Set `S3_FORCE_PATH_STYLE="true"` in your environment. This is required for most self-hosted S3-compatible services like MinIO, SeaweedFS, etc. ## Serve a public resume at the instance root To display one public resume at `/` instead of the marketing home, set the optional server environment variable `ROOT_RESUME_ID` on the application service: ```yaml theme={null} environment: APP_URL: https://resume.example.com ROOT_RESUME_ID: your-resume-id ``` Find the resume ID in its owner's builder URL: `/builder/`. The resume must already have **Allow Public Access** enabled in Sharing. This setting does not change its visibility. Password protection and the download-button preference still apply, and the ordinary `//` URL continues to work. Renaming the username or slug does not change the configured ID. Restart the application after setting or changing `ROOT_RESUME_ID`. With Docker Compose, run `docker compose up -d` to recreate the application with the new environment. Unset the variable or leave it blank, then restart, to restore the marketing home. A missing, deleted, or private target shows an unavailable page, including when its owner visits `/`. Keep `APP_URL` set to the public origin and proxy the whole application normally, including API, uploads, fonts, and assets. Root mode uses that configured origin for its canonical URL; it does not infer a domain from request headers. A successful password challenge returns visitors to `/`. This is a single-resume setting for one self-hosted instance. It does not register custom domains, manage DNS or TLS, or hide the rest of the application. Login and the dashboard remain available at their usual paths. # Docker Compose examples Source: https://docs.rxresu.me/self-hosting/examples Ready-to-use Docker Compose examples for self-hosting Reactive Resume with Postgres, Traefik, Caddy, Nginx Proxy Manager, and other common deployment stacks. **From v5.1.0 onwards** — PDF generation now runs entirely client-side via `@react-pdf/renderer`. None of the examples below require a Browserless or Chromium service. Older configurations that still define a `printer` service or set `BROWSERLESS_TOKEN` / `PRINTER_*` will continue to start, but those services are inert and can be removed. ## Overview Self-hosted setups vary. You might run on a single VPS or a Kubernetes cluster, behind Cloudflare Tunnel, or behind a reverse proxy like Traefik or nginx. This page collects Docker Compose configurations for those cases. They go further than the basic setup in the [Self-hosting with Docker](/self-hosting/docker) guide, with reverse proxies, SSL termination, and other common patterns. **Share your setup.** If you have a working configuration that isn't covered here, I'd love to include it. [Open a pull request](https://github.com/amruthpillai/reactive-resume) with your example added to this page. *** ## Reuse an existing PostgreSQL service Reactive Resume always uses a separate PostgreSQL service; do not embed another database server in the app container. If your homelab or hosting platform already manages PostgreSQL, reuse it by setting `DATABASE_URL` to that service and allowing the app container to reach it over the intended private network. Keep database credentials private and do not expose PostgreSQL to the public internet. When the database connection crosses a host or network boundary, require TLS with certificate and hostname verification. Use `sslmode=verify-full` in `DATABASE_URL` where the provider supports it, or the provider's equivalent verified-TLS configuration. Private routing limits exposure, but does not itself verify the database server's identity. For generic Unraid and homelab container fields, including the `localhost` networking warning, see [Unraid and other homelab platforms](/self-hosting/docker#unraid-and-other-homelab-platforms). The core resume workflow does not require Redis or S3. Redis is a separate optional dependency for the AI Agent workspace, while S3-compatible storage is optional unless you need features that require private object storage; see the [environment variable reference](/self-hosting/docker#environment-variables) for those boundaries. *** ## Docker with Traefik This example uses [Traefik](https://traefik.io/) as a reverse proxy with automatic SSL certificate management via Let's Encrypt. Postgres stays on an internal network. The Traefik dashboard is also routed, at `traefik.${DOMAIN}` behind basic auth — drop those labels if you do not want it reachable. Traefik discovers services through Docker labels and handles SSL certificates, so it needs very little configuration. ```yaml compose-traefik.yml lines expandable theme={null} services: traefik: image: traefik:v3.2 restart: unless-stopped command: - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" - "--certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL}" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - "--entrypoints.web.http.redirections.entryPoint.to=websecure" - "--entrypoints.web.http.redirections.entryPoint.scheme=https" ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - traefik_letsencrypt:/letsencrypt networks: - reactive_resume_network labels: - "traefik.enable=true" # Dashboard (optional, remove if not needed) - "traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)" - "traefik.http.routers.traefik.entrypoints=websecure" - "traefik.http.routers.traefik.tls.certresolver=letsencrypt" - "traefik.http.routers.traefik.service=api@internal" - "traefik.http.routers.traefik.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=${TRAEFIK_DASHBOARD_AUTH}" postgres: image: postgres:latest restart: unless-stopped environment: - POSTGRES_DB=postgres - POSTGRES_USER=postgres - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql networks: - reactive_resume_network healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"] interval: 10s timeout: 5s retries: 5 reactive_resume: image: amruthpillai/reactive-resume:latest restart: unless-stopped environment: - APP_URL=https://resume.${DOMAIN} - DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres - AUTH_SECRET=${AUTH_SECRET} # Add other optional env vars as needed (SMTP, S3, OAuth, etc.) volumes: - reactive_resume_data:/app/data networks: - reactive_resume_network depends_on: postgres: condition: service_healthy labels: - "traefik.enable=true" - "traefik.http.routers.reactive-resume.rule=Host(`resume.${DOMAIN}`)" - "traefik.http.routers.reactive-resume.entrypoints=websecure" - "traefik.http.routers.reactive-resume.tls.certresolver=letsencrypt" - "traefik.http.services.reactive-resume.loadbalancer.server.port=3000" healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then((r) => { if (!r.ok) process.exit(1); }).catch(() => process.exit(1));"] interval: 30s timeout: 10s retries: 3 networks: reactive_resume_network: driver: bridge volumes: traefik_letsencrypt: postgres_data: reactive_resume_data: ``` **Environment variables (`.env`):** ```bash .env theme={null} DOMAIN="example.com" ACME_EMAIL="admin@example.com" POSTGRES_PASSWORD="your-secure-postgres-password" AUTH_SECRET="your-auth-secret-from-openssl-rand-hex-32" # Optional: Traefik dashboard auth (generate with: htpasswd -nb admin password) TRAEFIK_DASHBOARD_AUTH="admin:$$apr1$$..." ``` *** ## Docker with nginx This example uses [nginx](https://nginx.org/) as a reverse proxy with SSL certificates (you'll need to provide your own certificates or use certbot separately). ```yaml compose-nginx.yml lines expandable theme={null} services: nginx: image: nginx:alpine restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./certs:/etc/nginx/certs:ro networks: - reactive_resume_network postgres: image: postgres:latest restart: unless-stopped environment: POSTGRES_DB: postgres POSTGRES_USER: postgres POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql networks: - reactive_resume_network healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"] interval: 10s timeout: 5s retries: 5 reactive_resume: image: amruthpillai/reactive-resume:latest restart: unless-stopped environment: - APP_URL=https://resume.${DOMAIN} - DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres - AUTH_SECRET=${AUTH_SECRET} # Add other optional env vars as needed (SMTP, S3, OAuth, etc.) volumes: - reactive_resume_data:/app/data networks: - reactive_resume_network depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then((r) => { if (!r.ok) process.exit(1); }).catch(() => process.exit(1));"] interval: 30s timeout: 10s retries: 3 networks: reactive_resume_network: driver: bridge volumes: postgres_data: reactive_resume_data: ``` **nginx configuration (`nginx.conf`):** ```nginx nginx.conf lines expandable theme={null} events { worker_connections 1024; } http { upstream reactive_resume { server reactive_resume:3000; } # Redirect HTTP to HTTPS server { listen 80; server_name _; return 301 https://$host$request_uri; } # HTTPS server server { listen 443 ssl http2; server_name resume.example.com; ssl_certificate /etc/nginx/certs/fullchain.pem; ssl_certificate_key /etc/nginx/certs/privkey.pem; # SSL configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # Proxy settings location / { proxy_pass http://reactive_resume; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_cache_bypass $http_upgrade; # Reasonable timeouts for app requests proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } # Increase max body size for resume uploads client_max_body_size 10M; } } ``` For automatic SSL certificates with nginx, consider using [certbot](https://certbot.eff.org/) with the `--nginx` plugin, or a companion container like [nginx-proxy-acme](https://github.com/nginx-proxy/acme-companion). *** ## Docker Swarm This example is a Docker Swarm deployment with health checks, rolling updates, and Traefik integration. It includes SeaweedFS for S3-compatible storage and a PostgreSQL database with custom configuration. Docker Swarm suits multi-node deployments that need high availability and simple scaling. Every service here starts at one replica; raise `deploy.replicas` on `reactive_resume` once you have more than one node. ```yaml compose-swarm.yml lines expandable theme={null} services: postgres: image: postgres:latest networks: - reactive_resume_network volumes: - reactive_resume_postgres_data:/var/lib/postgresql environment: - POSTGRES_DB=$POSTGRES_DB - POSTGRES_USER=$POSTGRES_USER - POSTGRES_PASSWORD=$POSTGRES_PASSWORD healthcheck: test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"] interval: 10s timeout: 5s retries: 5 start_period: 30s deploy: mode: replicated replicas: 1 seaweedfs: image: chrislusf/seaweedfs:latest command: server -s3 -filer -dir=/data -ip=0.0.0.0 networks: - reactive_resume_network volumes: - reactive_resume_seaweedfs_data:/data environment: - AWS_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY healthcheck: test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:8888"] interval: 30s timeout: 10s retries: 3 start_period: 30s deploy: mode: replicated replicas: 1 seaweedfs_create_bucket: image: quay.io/minio/mc:latest entrypoint: > /bin/sh -c " until mc alias set seaweedfs http://seaweedfs:8333 $S3_ACCESS_KEY_ID $S3_SECRET_ACCESS_KEY; do echo 'Waiting for SeaweedFS...'; sleep 2; done; mc mb seaweedfs/$S3_BUCKET --ignore-existing; " networks: - reactive_resume_network deploy: mode: replicated replicas: 1 reactive_resume: image: ghcr.io/amruthpillai/reactive-resume:latest networks: - traefik_network - reactive_resume_network volumes: - reactive_resume_data:/app/data environment: - APP_URL=$APP_URL - DATABASE_URL=$DATABASE_URL - AUTH_SECRET=$AUTH_SECRET - GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID - GOOGLE_CLIENT_SECRET=$GOOGLE_CLIENT_SECRET - GITHUB_CLIENT_ID=$GITHUB_CLIENT_ID - GITHUB_CLIENT_SECRET=$GITHUB_CLIENT_SECRET - LINKEDIN_CLIENT_ID=$LINKEDIN_CLIENT_ID - LINKEDIN_CLIENT_SECRET=$LINKEDIN_CLIENT_SECRET - SMTP_HOST=$SMTP_HOST - SMTP_PORT=$SMTP_PORT - SMTP_USER=$SMTP_USER - SMTP_PASS=$SMTP_PASS - SMTP_FROM=$SMTP_FROM - SMTP_SECURE=$SMTP_SECURE - S3_ACCESS_KEY_ID=$S3_ACCESS_KEY_ID - S3_SECRET_ACCESS_KEY=$S3_SECRET_ACCESS_KEY - S3_REGION=$S3_REGION - S3_ENDPOINT=$S3_ENDPOINT - S3_BUCKET=$S3_BUCKET healthcheck: test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health').then((r) => { if (!r.ok) process.exit(1); }).catch(() => process.exit(1));"] interval: 30s timeout: 10s retries: 3 start_period: 30s deploy: mode: replicated replicas: 1 labels: - "traefik.enable=true" - "traefik.http.routers.app.rule=Host(`rxresu.me`)" - "traefik.http.routers.app.entrypoints=websecure" - "traefik.http.routers.app.tls=true" - "traefik.http.services.app.loadbalancer.server.port=3000" configs: reactive_resume_postgres_config: name: reactive_resume_postgres_config external: true networks: traefik_network: external: true reactive_resume_network: name: reactive_resume_network driver: overlay attachable: true volumes: reactive_resume_postgres_data: name: reactive_resume_postgres_data reactive_resume_seaweedfs_data: name: reactive_resume_seaweedfs_data reactive_resume_data: name: reactive_resume_data ``` **Deploy the stack:** ```bash theme={null} docker stack deploy -c compose-swarm.yml reactive_resume ``` **Useful commands:** ```bash theme={null} # Check service status docker stack services reactive_resume # View logs for the app docker service logs -f reactive_resume_reactive_resume # Scale the app docker service scale reactive_resume_reactive_resume=3 # Remove the stack docker stack rm reactive_resume ``` This example assumes you have an external Traefik network already set up. Adjust the `traefik_network` reference and labels based on your Traefik configuration. *** ## Contributing your setup Have a different deployment setup that works well? Consider contributing it here. Some examples: * Kubernetes / Helm charts * Cloudflare Tunnel * Caddy reverse proxy * Docker with Portainer * Podman configurations * Cloud-specific deployments (AWS ECS, Google Cloud Run, Azure Container Apps) To contribute, [open a pull request](https://github.com/amruthpillai/reactive-resume) with your example added to this page. Include: 1. A brief description of when/why someone would use this setup 2. The complete Docker Compose (or equivalent) configuration 3. Any additional configuration files (nginx.conf, etc.) 4. Required environment variables # Migrating from v4 to v5 Source: https://docs.rxresu.me/self-hosting/migration Step-by-step guide to migrate a self-hosted Reactive Resume instance from v4 to v5, covering database schema changes, manual and automated options. ## Overview To move a Reactive Resume installation from **v4 to v5**, you set up a new v5 instance alongside your existing v4 instance, then transfer your users and resumes across. This page is for **v4 → v5 data migration** only. For normal v5 upgrades, use the [Self-Hosting with Docker](/self-hosting/docker) guide. v5 schema migrations run automatically on app startup. This guide applies only to infrastructure and backups you are authorized to operate. It does not grant access to hosted Reactive Resume data. Only the hosted service operator can verify whether a hosted snapshot exists and authorize access to it. **Keep your v4 instance running** until you have migrated all data to v5 and checked that everything works. That way you have a fallback if the migration goes wrong. ## Prerequisites Before starting the migration, ensure you have: Your existing Reactive Resume v4 instance should be running and accessible. A fresh Reactive Resume v5 instance set up and running. Follow the [Self-hosting with Docker](/self-hosting/docker) guide if you haven't done this yet. Access to both your v4 PostgreSQL database (source) and v5 PostgreSQL database (target). A recent backup of your v4 database. Always back up before any migration. ## Choosing a migration method The best migration approach depends on the size of your instance: **Best for**: Small instances with a handful of resumes. Uses the built-in Import Dialog to manually convert resumes one at a time. **Best for**: Large instances with many users and resumes. Uses migration scripts to batch-process all users and resumes automatically. ## Recover one owner's resumes without overwriting v5 Use a recovery case when an owner changed resumes after an earlier migration. Keep the case record private and outside Git because it may connect account and resume identifiers. Record these fields before inspecting resume content: * Recovery case ID * Source snapshot capture time * Owner verification status * Source resume ID and mapped target resume ID, if one exists * Source and target content hashes * Proposed outcome: `no-op`, `export-copy`, or `blocked` Case IDs, source resume IDs, and non-null target resume IDs must contain a non-whitespace character after trimming and must not contain Unicode control or format characters. Valid identifiers are preserved verbatim. These hashes prove content equality only; they never prove ownership, source authenticity, or recipient identity. An authorized operator should follow this order: Confirm that a source snapshot exists and record when it was captured. If no source snapshot exists, report that factual limit. Recovery tooling cannot reconstruct records that are absent from every available source. Verify the requester using the operator's approved account-ownership process. Confirm the old-to-new owner mapping; a matching email address, resume title, or username alone is not ownership proof. Stop if either check is incomplete. Build one serialized JSON comparison request containing the case IDs, safety flags, and source and target values. The comparator accepts only this request string, not an object argument. Source and target data must already conform exactly to the current v5 resume-data schema before content hashes are calculated. Raw v4 exports are unsupported, and the comparator performs no format conversion. Identical content is a `no-op`. Source-only or divergent content is an `export-copy`. Missing identity evidence, mapping, valid current-v5 data, or a source snapshot is `blocked`. Default to a private JSON export. Never overwrite the current v5 resume. After the recipient and delivery channel are approved, deliver the recovered JSON privately so the owner can import it as a separate resume. Record source and delivered hashes outside Git and confirm they match. Repository contributors can rehearse this decision with the pure comparator in `tooling/recovery/compare-resume.ts`. It accepts one serialized JSON comparison request and rejects object arguments. The request's source and target values must already conform exactly to the current v5 resume-data schema. It does not accept raw v4 exports or perform legacy conversion; review the historical converter at tag `v5.0.20` separately before processing legacy-format data. The comparator produces a deterministic dry-run manifest and has no database, network, or write path. Use synthetic IDs and content only; keep any operational manifest outside the repository. ## Manual migration (small instances) If you have only a few resumes to migrate, the simplest approach is to use the **Import Dialog** feature in v5. In your v4 instance, go to each resume and export it as JSON. This creates a portable file containing all your resume data. In your new v5 instance: 1. Sign in or create a new account 2. Click **Create Resume** or use the **Import** option 3. Select the **Reactive Resume v4** format 4. Upload your exported JSON file The import process automatically converts the v4 format to v5. Review the imported resume to ensure all data transferred correctly. Repeat for each resume you need to migrate. The Import Dialog handles the schema conversion automatically, so you don't need to worry about format differences between v4 and v5. ## Automated migration (large instances) For instances with many users and resumes, use the migration scripts to automate the process. The migration happens in two phases: first users, then resumes. ### Requirements To run the migration scripts, you need the following installed on your host machine: **tsx** - TypeScript execution environment. Install globally with: `bash npm install -g tsx ` **dotenvx** (or any tool to load `.env` files). Install globally with: `bash npm install -g @dotenvx/dotenvx ` Alternatively, you can use `dotenv`, `direnv`, or export the variables manually. Clone the Reactive Resume repository and check out the last tag that includes the migration scripts: ```bash theme={null} git clone https://github.com/amruthpillai/reactive-resume.git cd reactive-resume git checkout tags/v5.0.20 pnpm install ``` The v4 migration scripts live in the `v5.0.20` tag. Use that checkout only to run the migration scripts against your v4 and v5 databases; keep your actual v5 deployment on the latest version. ### Environment setup Create a `.env` file in the root of the repository with the following variables: ```bash .env theme={null} # Connection string to your NEW v5 PostgreSQL database (target) DATABASE_URL="postgresql://user:password@localhost:5432/reactive_resume_v5" # Connection string to your OLD v4 PostgreSQL database (source) PRODUCTION_DATABASE_URL="postgresql://user:password@localhost:5432/reactive_resume_v4" ``` Double-check your connection strings! `DATABASE_URL` should point to your **new v5 database** and `PRODUCTION_DATABASE_URL` should point to your **old v4 database**. Mixing these up could cause data loss. `PRODUCTION_DATABASE_URL` is used only by these migration scripts. It is not a runtime app variable. ### Step 1: Migrate users The user migration script transfers all user accounts, authentication data, and two-factor settings from v4 to v5. ```bash theme={null} dotenvx run -- tsx scripts/migration/user.ts ``` **What this script does:** * Fetches users in batches from the v4 database * Creates corresponding user accounts in the v5 database * Migrates authentication providers (email, Google, GitHub, custom OAuth) * Preserves two-factor authentication settings and backup codes * Creates a mapping file (`scripts/migration/user-id-map.json`) that links old user IDs to new ones The script saves progress automatically. If interrupted (Ctrl+C), you can run it again and it will resume from where it left off. **Expected output:** ``` ⌛ Starting user migration... 📥 Fetching users batch from production database (OFFSET 0)... 📋 Found 1000 users in this batch. 📝 Preparing to bulk insert 1000 users... ✅ Bulk inserted 1000 users in 245.3 ms (avg 0.2 ms/user) 💾 Progress saved at offset 1000 📦 Processed 1000 users so far... 📊 Migration Summary: Users created: 1000 Accounts created: 1000 Two-factor entries created: 50 Skipped (already exist): 0 ⏱️ Total migration time: 1234.5 ms (1.23 seconds) ✅ User migration complete! ``` ### Step 2: Migrate resumes After users are migrated, run the resume migration script. This script depends on the user ID mapping created in the previous step. ```bash theme={null} dotenvx run -- tsx scripts/migration/resume.ts ``` **What this script does:** * Fetches resumes in batches from the v4 database * Converts each resume from v4 format to v5 format automatically * Links resumes to the correct users using the ID mapping * Migrates resume statistics (views, downloads) * Preserves visibility settings (public/private) and lock status Like the user script, the resume migration also saves progress and can be resumed if interrupted. **Expected output:** ``` ⌛ Starting resume migration... 📥 Fetching resumes batch from production database (OFFSET 0)... 📋 Found 2500 resumes in this batch. 📝 Preparing to bulk insert 2500 resumes... ✅ Bulk inserted 2500 resumes in 892.1 ms (avg 0.4 ms/resume) 💾 Progress saved at offset 2500 📦 Processed 2500 resumes so far... 📊 Migration Summary: Resumes created: 2500 Statistics created: 2500 Skipped (userId not found or already exist): 0 Errors: 0 ⏱️ Total migration time: 5678.9 ms (5.68 seconds) ✅ Resume migration complete! ``` ### Progress and recovery Both migration scripts support graceful shutdown and resume: * **Progress files**: `scripts/migration/user-progress.json` and `scripts/migration/resume-progress.json` track the current migration state * **User ID mapping**: `scripts/migration/user-id-map.json` maps v4 user IDs to v5 user IDs * **Graceful shutdown**: Press `Ctrl+C` to stop the migration safely. Progress is saved before exit. * **Resume migration**: Run the script again to continue from where you left off Preserve progress files and the user ID mapping as recovery evidence. Do not delete them or replay the historical scripts against a populated target as a recovery shortcut. Review the `v5.0.20` scripts, source backup, mapping, and target state before any rerun. ## Post-migration steps After completing the migration: Sign in to your v5 instance and spot-check several user accounts and resumes to ensure data transferred correctly. * Create a test resume and export it as PDF - Verify social sign-in works (if configured) - Check that two-factor authentication works for migrated users Once verified, update your DNS records or reverse proxy to point to the new v5 instance. After confirming everything works and allowing a grace period, you can safely shut down your v4 instance. ## Important notes Users who signed up with email/password can continue using their existing passwords. No password reset is required after migration. User profile pictures (avatars) are stored as references in the database. If you were using S3 storage, ensure your v5 instance has access to the same bucket, or users may need to re-upload their avatars. Similar to profile pictures, any images embedded in resumes need to be accessible from your v5 instance. Consider migrating your storage bucket or updating references as needed. If you're using custom OAuth providers, ensure the same providers are configured in v5 with matching client IDs. Users authenticate with the same provider ID, so mismatched configurations will cause login failures. The v5 schema has some changes from v4: * `visibility` (public/private) is now `isPublic` (boolean) * Resume `title` is now `name` * Some resume data fields have been reorganized The migration scripts handle these conversions automatically. ## Troubleshooting Ensure your `.env` file contains both `DATABASE_URL` and `PRODUCTION_DATABASE_URL`, and that you're using a tool like `dotenvx` to load them before running the script. Users are skipped if: - Their email already exists in the v5 database - Their username already exists in the v5 database - They were already migrated in a previous run Check the console output for skip reasons. Resumes are skipped if: - The associated user wasn't migrated (user ID not in mapping file) - A resume with the same slug already exists for that user - They were already migrated in a previous run Historical scripts can create default empty data when a v4 resume cannot be parsed. Treat that result as a failed conversion, not a recovered resume. Preserve the source export, review the `v5.0.20` converter, and use the Import Dialog only after valid source data is confirmed. The scripts process data in batches to avoid overwhelming the database. For very large instances: * Consider running the migration during off-peak hours * Ensure both databases have adequate resources * The batch size can be adjusted in the script files if needed # Single Sign-On (SSO) Source: https://docs.rxresu.me/self-hosting/sso Configure Single Sign-On for self-hosted Reactive Resume using custom OAuth providers like Authentik, Authelia, Keycloak, or any OIDC-compliant IdP. ## Overview Reactive Resume supports custom OAuth providers, so you can sign in through an enterprise identity provider or a self-hosted authentication service. This helps organizations that want to: * Use a centralized identity provider (Authentik, Authelia, Keycloak, etc.) * Enforce Single Sign-On (SSO) across all internal applications * Integrate with existing LDAP/Active Directory infrastructure Custom OAuth is for **self-hosted instances**. If you're using the hosted version at [rxresu.me](https://rxresu.me), you can use the built-in Google and GitHub sign-in options. ## Environment variables To enable a custom OAuth provider, you need to configure the following environment variables in your `.env` file: ### Required variables | Variable | Description | | --------------------- | ------------------------------------------------- | | `OAUTH_CLIENT_ID` | The client ID provided by your OAuth provider | | `OAUTH_CLIENT_SECRET` | The client secret provided by your OAuth provider | ### Endpoint configuration You must configure endpoints using **one** of these two methods: For OIDC-compliant providers (most modern identity providers), you only need to set the discovery URL: | Variable | Description | | --------------------- | ------------------------------------------------------ | | `OAUTH_DISCOVERY_URL` | Your provider's `.well-known/openid-configuration` URL | The discovery URL automatically provides the authorization, token, and userinfo endpoints. **Examples:** * Authentik: `https://auth.example.com/application/o/reactive-resume/.well-known/openid-configuration` * Keycloak: `https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration` * Authelia: `https://auth.example.com/.well-known/openid-configuration` For providers that don't support OIDC discovery, you must set all three URLs: | Variable | Description | | ------------------------- | -------------------------------------------------- | | `OAUTH_AUTHORIZATION_URL` | The URL where users are redirected to authorize | | `OAUTH_TOKEN_URL` | The URL to exchange authorization codes for tokens | | `OAUTH_USER_INFO_URL` | The URL to fetch user profile information | ### Optional variables | Variable | Description | Default | | --------------------- | ---------------------------------------- | ---------------------- | | `OAUTH_PROVIDER_NAME` | Display name shown on the sign-in button | `Custom OAuth` | | `OAUTH_SCOPES` | Space-separated list of OAuth scopes | `openid profile email` | ## Callback URL When configuring your OAuth provider, you'll need to set the **callback URL** (also called redirect URI). Use the following format: ``` {APP_URL}/api/auth/callback/custom ``` For example, if your `APP_URL` is `https://resume.example.com`, the callback URL would be: ``` https://resume.example.com/api/auth/callback/custom ``` Make sure the callback URL exactly matches what you configure in your OAuth provider. A mismatch will cause authentication to fail. **Upgrading an existing install:** the callback path changed from `/api/auth/oauth2/callback/custom` to `/api/auth/callback/custom`. Update the redirect URI registered with your identity provider, or custom OAuth sign-in will fail after the upgrade. **Upgrading an existing install with `OAUTH_DISCOVERY_URL`:** accounts are now identified by the issuer your provider advertises, and the automatic migration cannot know that value ahead of time. It backfills existing rows with the placeholder `local:oauth:custom`. After upgrading, run the following once, replacing the value with the `issuer` field from your discovery document (`{OAUTH_DISCOVERY_URL}` returns it as JSON): ```sql theme={null} UPDATE account SET issuer = 'https://auth.example.com/realms/main' WHERE provider_id = 'custom'; ``` Skipping this does not lose data, but existing users signing in through your provider will no longer match their account. If you configure the provider with explicit `OAUTH_AUTHORIZATION_URL` / `OAUTH_TOKEN_URL` endpoints instead of discovery, the placeholder is already correct and no action is needed. Built-in providers (Google, GitHub, LinkedIn) use callback URLs in this format: `{APP_URL}/api/auth/callback/ {provider}` (for example `.../google`, `.../github`, `.../linkedin`). ## URL and proxy requirements * Set `APP_URL` to the exact public URL users access (prefer HTTPS in production). * Auth metadata, JWKS, and OAuth callback URLs are derived from `APP_URL`. * Behind a reverse proxy, forward `Host` and `X-Forwarded-Proto` correctly, or cookie/session behavior may break. * `trustedOrigins` are derived from `APP_URL`, so alternate domains are not automatically trusted. ## Profile mapping Reactive Resume maps user profile data from the OAuth provider using these fields: | Reactive Resume Field | OAuth Profile Fields (in order of preference) | | --------------------- | --------------------------------------------- | | **Email** (required) | `email` | | **Name** | `name` → `preferred_username` → email prefix | | **Username** | `preferred_username` → email prefix | | **Avatar** | `image` → `picture` → `avatar_url` | The OAuth provider **must** return an email address. If no email is provided, authentication will fail with an error. ## Provider-specific setup ### Authentik In the Authentik admin interface, navigate to **Applications → Providers** and create a new **OAuth2/OpenID Provider**. * **Name**: Reactive Resume * **Authorization flow**: Use your preferred authorization flow * **Client type**: Confidential * **Redirect URIs**: `https://resume.example.com/api/auth/callback/custom` Navigate to **Applications → Applications** and create a new application: * **Name**: Reactive Resume * **Slug**: `reactive-resume` * **Provider**: Select the provider you just created From the provider settings, copy the **Client ID** and **Client Secret**. ```bash .env theme={null} OAUTH_PROVIDER_NAME="Authentik" OAUTH_CLIENT_ID="your-client-id" OAUTH_CLIENT_SECRET="your-client-secret" OAUTH_DISCOVERY_URL="https://auth.example.com/application/o/reactive-resume/.well-known/openid-configuration" ``` ### Authelia Add a client configuration to your Authelia `configuration.yml`: ```yaml theme={null} identity_providers: oidc: clients: - client_id: reactive-resume client_name: Reactive Resume client_secret: "your-hashed-secret" # Use authelia hash-password to generate public: false authorization_policy: two_factor # or one_factor redirect_uris: - https://resume.example.com/api/auth/callback/custom scopes: - openid - profile - email token_endpoint_auth_method: client_secret_post ``` Generate the hashed secret using: `authelia crypto hash generate pbkdf2 --variant sha512` ```bash .env theme={null} OAUTH_PROVIDER_NAME="Authelia" OAUTH_CLIENT_ID="reactive-resume" OAUTH_CLIENT_SECRET="your-plain-secret" OAUTH_DISCOVERY_URL="https://auth.example.com/.well-known/openid-configuration" ``` Use the **plain text** secret in Reactive Resume's environment, not the hashed version used in Authelia's configuration. ### Keycloak In the Keycloak admin console: 1. Select your realm 2. Navigate to **Clients → Create client** 3. Set **Client ID** (e.g., `reactive-resume`) 4. Set **Client authentication** to **On** 5. Enable **Standard flow** In the client settings, add the redirect URI: * **Valid redirect URIs**: `https://resume.example.com/api/auth/callback/custom` Go to the **Credentials** tab and copy the **Client secret**. ```bash .env theme={null} OAUTH_PROVIDER_NAME="Keycloak" OAUTH_CLIENT_ID="reactive-resume" OAUTH_CLIENT_SECRET="your-client-secret" OAUTH_DISCOVERY_URL="https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration" ``` ### Generic OIDC provider For any other OIDC-compliant provider: ```bash .env theme={null} OAUTH_PROVIDER_NAME="My SSO" OAUTH_CLIENT_ID="your-client-id" OAUTH_CLIENT_SECRET="your-client-secret" OAUTH_DISCOVERY_URL="https://sso.example.com/.well-known/openid-configuration" ``` ### Non-OIDC provider (manual configuration) For providers that don't support OIDC discovery: ```bash .env theme={null} OAUTH_PROVIDER_NAME="Custom Provider" OAUTH_CLIENT_ID="your-client-id" OAUTH_CLIENT_SECRET="your-client-secret" OAUTH_AUTHORIZATION_URL="https://provider.example.com/oauth/authorize" OAUTH_TOKEN_URL="https://provider.example.com/oauth/token" OAUTH_USER_INFO_URL="https://provider.example.com/oauth/userinfo" OAUTH_SCOPES="openid profile email" ``` ## Complete example Here's a complete `.env` snippet showing custom OAuth alongside other authentication options: ```bash .env theme={null} # --- Authentication --- AUTH_SECRET="your-32-byte-hex-secret" # Built-in Social Auth (optional, can coexist with custom OAuth) # GOOGLE_CLIENT_ID="" # GOOGLE_CLIENT_SECRET="" # GITHUB_CLIENT_ID="" # GITHUB_CLIENT_SECRET="" # LINKEDIN_CLIENT_ID="" # LINKEDIN_CLIENT_SECRET="" # Custom OAuth Provider (e.g., Authentik) OAUTH_PROVIDER_NAME="Company SSO" OAUTH_CLIENT_ID="reactive-resume-client-id" OAUTH_CLIENT_SECRET="reactive-resume-client-secret" OAUTH_DISCOVERY_URL="https://auth.company.com/application/o/reactive-resume/.well-known/openid-configuration" # OAUTH_SCOPES="openid profile email" # Defaults to these scopes if not set ``` ## Troubleshooting Your OAuth provider must return an email address for user creation. Ensure: * The `email` scope is included in your scopes * Your provider is configured to release the email claim * The user has an email address set in the identity provider The callback URL configured in your OAuth provider must exactly match: ` {APP_URL}/api/auth/callback/custom` Common issues: - Trailing slash mismatch - HTTP vs HTTPS mismatch - Port number differences - Path case sensitivity Common cause: `APP_URL` does not match the real HTTPS public origin (for example, app is behind TLS but `APP_URL` is `http://...`). Fix: set `APP_URL` to the canonical HTTPS URL and restart the app. The custom OAuth option only appears if both `OAUTH_CLIENT_ID` and `OAUTH_CLIENT_SECRET` are set, **and** either: * `OAUTH_DISCOVERY_URL` is set, **or** * All three manual URLs are set (`OAUTH_AUTHORIZATION_URL`, `OAUTH_TOKEN_URL`, `OAUTH_USER_INFO_URL`) Double-check your environment variables and restart the container. If running behind a reverse proxy: - Ensure `APP_URL` matches your public URL - Verify the proxy passes the correct headers (`X-Forwarded-Proto`, `X-Forwarded-Host`) - Check that your OAuth provider allows the redirect URI from your domain Dynamic OAuth client registration allows the app origin and local loopback callbacks by default. Trusted self-hosted deployments that need arbitrary redirect URIs can enable `FLAG_ALLOW_UNSAFE_OAUTH_REDIRECT_URI`, which permits any parseable redirect URI including custom schemes, private hosts, and non-loopback `http://` URLs. Do not enable it on public or multi-tenant deployments. The profile mapping depends on your provider returning standard claims: * `email` (required) * `name` or `preferred_username` for display name * `picture`, `image`, or `avatar_url` for avatar Check your provider's documentation to ensure these claims are included in the ID token or userinfo response. ## Security considerations Always use HTTPS for both your Reactive Resume instance and OAuth provider in production. OAuth tokens should never be transmitted over unencrypted connections. Never commit `OAUTH_CLIENT_SECRET` to version control. Use environment variables or a secrets manager. Configure your OAuth provider to only allow the exact redirect URI. Avoid wildcards in redirect URI configurations. Keep `AUTH_SECRET` and `BETTER_AUTH_API_KEY` private. Rotating `AUTH_SECRET` may invalidate active sessions. Only request the scopes you need. The default (`openid profile email`) is sufficient for Reactive Resume. # AI resume builder Source: https://docs.rxresu.me/use-cases/ai-resume-builder Use Reactive Resume as an AI resume builder with bring-your-own OpenAI, Anthropic, Gemini, OpenRouter, or Ollama providers for edits and drafts. Reactive Resume works as an AI-assisted resume builder, but the AI is optional and bring-your-own-provider: you configure the provider, model, endpoint, and API key you want it to use. ## What AI does in Reactive Resume AI can make assisted changes in the builder, review your writing in the ATS checker, produce agent drafts, and support import workflows. The builder and the ATS checker both work without it. Use these guides for the full setup: * [Using artificial intelligence](/guides/using-ai) * [Using AI in the builder](/guides/using-ai-in-the-builder) * [Using the AI Agent workspace](/guides/using-ai-agent) * [AI Agent tools](/guides/ai-agent-tools) ## Bring your own provider You configure an AI provider from the Integrations settings: the provider type, the model, a base URL when one is needed, and the API key. This is not a hosted AI-writing product. You decide whether to enable AI, which provider to connect, and when to send resume content to it. ## Where AI fits in the workflow AI helps most once you already have resume content or structured source material. Review its suggestions, apply changes in the builder, or use agent drafts as separate workspaces before deciding what belongs in the final resume. ## When not to use AI Do not use AI features if you do not want your resume content sent to the provider you configure. Do not treat AI output as final application material without reviewing it, and use the regular builder when you need exact control over the wording. ## Next action Configure and test a provider with [Using artificial intelligence](/guides/using-ai). Then use [Using AI in the builder](/guides/using-ai-in-the-builder) for in-place help, or [Using the AI Agent workspace](/guides/using-ai-agent) for draft-based work. Review AI-generated resume content before using it in applications. You are responsible for the accuracy of the final resume. # API and MCP resume automation Source: https://docs.rxresu.me/use-cases/api-mcp-resume-automation Automate resume workflows in Reactive Resume with API keys, the Patch API, the MCP server, AI agent tools, and the JSON resume schema. Reactive Resume supports automation through authenticated API access and an MCP server, so compatible tools can work with your resumes and job applications. Agents can list, read, create, import, duplicate, and patch resumes. They can also track applications, move opportunities through stages, add notes and follow-ups, attach sent documents, and run Application Copilot actions. ## Automation options Use the API for direct programmatic access from scripts, services, or integrations. Use MCP when you want an AI tool or agent that speaks the Model Context Protocol to work with your resumes through exposed tools. Key docs: * [Using the API](/guides/using-the-api) * [Using the patch API](/guides/using-the-patch-api) * [Using the MCP server](/guides/using-the-mcp-server) * [AI Agent tools](/guides/ai-agent-tools) * [JSON Resume schema](/guides/json-resume-schema) ## Common automation workflows You can build workflows that: * Create a resume from structured data. * Import a full resume JSON document. * Read resume data for review or transformation. * Patch targeted fields without replacing the whole resume. * Connect an MCP-compatible client to operate on resumes with authenticated tools. * Track job applications end to end from an MCP client. * Import existing application rows from a spreadsheet parser. * Move applications through stages and log timeline notes. * Attach the resume or cover-letter PDF sent for an application. * Score a linked resume against a job description and create a tailored resume copy. * Draft cover letters and recruiter follow-ups from saved application context. Start with the Patch API for targeted resume updates. It is the safest option because it is built around explicit changes to existing resume data. ## Authentication and scope API requests use API keys. MCP can use OAuth2 in clients that support it, with API keys as a fallback. If you self-host, use your own instance URL for the API and MCP endpoints. Automation changes affect the resumes available to the authenticated account or instance. Test workflows on a copy of a resume before using them for important application materials. ## When not to use automation Do not reach for API or MCP automation when you only need to edit one resume by hand. The builder is faster for one-off changes, template selection, and visual review. Avoid automation for important resume updates unless you can test the exact changes on a copy first. ## Next action For scripts and integrations, create an API key with [Using the API](/guides/using-the-api), then use [Using the patch API](/guides/using-the-patch-api) for targeted edits. For agent workflows, start with [Using the MCP server](/guides/using-the-mcp-server). # Export and share resumes Source: https://docs.rxresu.me/use-cases/export-and-share-resumes Export Reactive Resume resumes as PDF, DOCX, Markdown, or JSON files and share password-protected public URLs with recruiters and hiring managers. Reactive Resume exports resumes as PDFs, and it can also give you a public resume URL to send to a person: a recruiter, a hiring manager, a collaborator, or a visitor to your portfolio. Public resume URLs are not search-indexed by default. ## Export a PDF Export a PDF when an application requires a file upload, or when you want a fixed document to send by email. See [Exporting your resume](/guides/exporting-your-resume) for the export workflow. ## When to export Export a PDF when a job application requires an uploaded document, when you need a fixed copy for your records, or when you want to send a file that will not change after you submit it. ## When to share a link Share a public resume URL when the recipient can open a link and you want them to see the current version of your resume. ## Share a public resume URL Public sharing creates a URL you can send to someone else. The page shows the current version of your resume and can offer a download to viewers. Public resume URLs are meant for people who get the link from you or find it through you. ## When not to share only a link Do not send only a public URL when an application requires a PDF or document upload. Do not use public sharing for a restricted audience unless you turn on password protection, or keep the resume private until you are ready. See [Sharing your resume publicly](/guides/sharing-your-resume-publicly) for setup, password protection, statistics, and how to turn public access off. ## Use the builder dock The builder dock has shortcuts for common editing and sharing actions inside the resume builder. See [Using the builder dock](/guides/using-the-builder-dock) for the available actions. Download a fixed resume file. Share a live resume URL with selected recipients. ## Next action Use [Exporting your resume](/guides/exporting-your-resume) if you need a file, or [Sharing your resume publicly](/guides/sharing-your-resume-publicly) if a link will do. # Free resume builder Source: https://docs.rxresu.me/use-cases/free-resume-builder Reactive Resume is a free resume builder with no paywalls or premium tiers for creating, editing, exporting, and sharing unlimited resumes online. Reactive Resume is a free resume builder. Write your resume in a browser, pick a template, export a PDF, and share a public URL when you want someone else to read it. Public resume URLs are meant for people you send them to, and they are not search-indexed by default. ## What you can do for free * Create and manage resumes from the dashboard. * Edit resume content with a live preview in the builder. * Choose from the templates included with Reactive Resume. * Export your resume as a PDF. * Share a public resume URL with recruiters, hiring managers, or collaborators. Start with [Introduction](/getting-started) for the product overview, or follow the [Quickstart](/getting-started/quickstart) to create your first resume on [rxresu.me](https://rxresu.me). ## Builder workflow Reactive Resume sticks to the core resume workflow: add your profile, work history, education, skills, projects, and other sections, then adjust the layout and template before exporting. Useful guides: * [Creating your first resume](/guides/creating-your-first-resume) * [Choosing a template](/guides/choosing-a-template) * [Fitting content on a page](/guides/fitting-content-on-a-page) * [Using the builder dock](/guides/using-the-builder-dock) ## When to use this path Use the hosted app when you want a resume quickly and do not want to run any infrastructure. It covers personal resume editing, template selection, PDF export, and sharing a public URL with people who need to read your resume. ## When not to use this path Do not rely on the hosted app alone if your organization requires a controlled deployment, custom auth, or specific data residency rules. Review [Self-hosting with Docker](/self-hosting/docker) instead. If an application requires a file upload, export a PDF rather than sending only a public URL. ## Export and sharing options Download a PDF for applications that need a file. You can also turn on a public resume URL when a link is more convenient than an attachment. Public resume URLs are for the people you send the link to. For details, see [Exporting your resume](/guides/exporting-your-resume) and [Sharing your resume publicly](/guides/sharing-your-resume-publicly). ## Next action Open [rxresu.me](https://rxresu.me) to create a resume, or follow [Creating your first resume](/guides/creating-your-first-resume) for the guided workflow. ## Related resources Open the official Reactive Resume instance. View the project repository. Review the project license. Learn how the hosted service describes data handling. # Open-source resume builder Source: https://docs.rxresu.me/use-cases/open-source-resume-builder Learn how Reactive Resume works as an open-source resume builder with public source code, an MIT license, and self-hosting support. Reactive Resume is an open-source resume builder. The source code is public, the license is MIT, and you can either use the hosted app or run your own instance. ## What open source means here The project repository is on [GitHub](https://github.com/amruthpillai/reactive-resume). You can read the code, report issues, contribute improvements, and see how the builder, the API, the self-hosting setup, and the documentation are put together. The license is documented in [License](/legal/license). ## Product capabilities Reactive Resume has a browser-based builder, resume templates, PDF export, public sharing links, API access, MCP support, and optional AI-assisted workflows. Public resume URLs are meant for the people you share them with and are not search-indexed by default. The main workflow starts in the hosted app at [rxresu.me](https://rxresu.me) or on your own deployment. Helpful starting points: * [Introduction](/getting-started) * [Quickstart](/getting-started/quickstart) * [Creating your first resume](/guides/creating-your-first-resume) * [Managing resumes from the dashboard](/guides/managing-resumes-from-the-dashboard) ## When to use this path Use the open-source path when you want to see how resume data and exports are handled, contribute fixes or translations, or keep the option of running your own deployment. ## When not to use this path Do not start with the source code if you only want to build a resume. Use [rxresu.me](https://rxresu.me) or the [Quickstart](/getting-started/quickstart) first. Do not assume open source covers your compliance needs on its own; if you run an instance, read the self-hosting and privacy docs. ## Contribution and customization To contribute or to understand the codebase, start with the contributor docs. They cover the local development setup, the package layout, and the project conventions. Set up the repository locally. Understand the app and package boundaries. Help translate the app. Browse issues, pull requests, and source code. ## Next action To contribute, set up the project with [Development setup](/contributing/development). To run it yourself, start with [Self-hosting with Docker](/self-hosting/docker). # Privacy-focused resume builder Source: https://docs.rxresu.me/use-cases/privacy-focused-resume-builder Reactive Resume's privacy-focused design: open-source transparency, self-hosting, public sharing controls, and optional bring-your-own AI providers. Reactive Resume is a privacy-focused resume builder: the code is open source, you can self-host it, editing is private by default, and both sharing and AI are choices you make yourself. ## Privacy controls in the resume workflow You edit resumes inside your account. When you want someone else to read one, turn on a public URL and send them the link. Public resume URLs are not search-indexed by default. You can turn public access off again, and a public resume can require a password. For the sharing workflow, see [Sharing your resume publicly](/guides/sharing-your-resume-publicly). For account security, see [Setting up two-factor authentication](/guides/setting-up-two-factor-authentication) and [Setting up passkeys](/guides/setting-up-passkeys). ## When to use this path Use this path when you want to understand the tradeoffs before choosing hosted use, self-hosting, public sharing, API automation, or AI features. It matters most if your resume holds sensitive job-search information, or if you plan to share links with only a few people. ## When not to use this path Do not treat public sharing as access control. Use password protection, or keep the resume private, if only specific people should open the link. Do not turn on AI features unless you are comfortable sending the prompts and resume content to the provider you configure. ## Open source and self-hosting The source code is on [GitHub](https://github.com/amruthpillai/reactive-resume), so you can read how the application works. If you need direct control over infrastructure, storage, auth providers, and deployment policy, run your own instance. Start with: * [Self-hosting with Docker](/self-hosting/docker) * [Self-hosting examples](/self-hosting/examples) * [Single sign-on](/self-hosting/sso) * [Privacy Policy](/legal/privacy-policy) ## Optional AI features AI is optional. Reactive Resume does not need it to create, edit, export, or share a resume. If you do want AI help, you configure the provider and the key yourself. For setup details, see [Using artificial intelligence](/guides/using-ai), [Using AI in the builder](/guides/using-ai-in-the-builder), and [Using the AI Agent workspace](/guides/using-ai-agent). Review the privacy policy for the instance you use. If you self-host, you are responsible for the deployment's data handling, storage, email, and third-party provider configuration. ## Next action Read the [Privacy Policy](/legal/privacy-policy), then go to [Sharing your resume publicly](/guides/sharing-your-resume-publicly) for link controls or [Self-hosting with Docker](/self-hosting/docker) for infrastructure control. # Self-hosted resume builder Source: https://docs.rxresu.me/use-cases/self-hosted-resume-builder Run Reactive Resume as a self-hosted resume builder with Docker Compose, PostgreSQL, optional object storage, Single Sign-On, and v4 to v5 migration. You can run Reactive Resume on your own infrastructure instead of using the hosted instance. ## When self-hosting is a good fit Self-hosting helps when you need control over the deployment, domain, database, storage, email delivery, authentication providers, and operational policy. The Docker guide is the main setup path for most deployments. Start here: * [Self-hosting with Docker](/self-hosting/docker) * [Self-hosting examples](/self-hosting/examples) * [Single sign-on](/self-hosting/sso) * [Migration guide](/self-hosting/migration) ## Core deployment pieces A typical self-hosted deployment uses: * Reactive Resume application container. * PostgreSQL database. * SMTP configuration for account emails, or console-logged emails in simple development setups. * Optional S3-compatible storage for uploads. * Optional SSO or custom OAuth configuration. The Docker guide has the environment variable reference and a Compose example. ## Feature considerations Some features need extra configuration. Saved AI providers need server-side encryption configured, and the AI Agent workspace uses Redis. Self-hosted deployments can also expose API and MCP endpoints from their own domain. For automation setup on a self-hosted instance, see [Using the API](/guides/using-the-api) and [Using the MCP server](/guides/using-the-mcp-server). Replace hosted URLs such as [https://rxresu.me](https://rxresu.me) with your own instance URL when following API, MCP, or sharing examples.