Compare commits

..
365 Commits
Author SHA1 Message Date
Amruth Pillai 1b266ba7ac Implement Resume Analysis (#2882)
* Implement Resume Analysis

* 📦 v5.0.17 - https://docs.rxresu.me/changelog
2026-04-09 09:04:27 +02:00
Amruth Pillai 1810dc8b07 better mcp server 2026-04-09 00:28:31 +02:00
Amruth Pillai 06b9da39ed Sync Translations from Crowdin (#2864)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (English, United Kingdom)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]
2026-04-05 09:50:40 +02:00
Amruth Pillai 11373763fd fixes #2868 2026-04-05 09:03:49 +02:00
Amruth Pillai b3224ce59b Merge branch 'main' of github.com:amruthpillai/reactive-resume 2026-04-04 20:59:38 +02:00
Amruth Pillai 145b17de0f fix #2865, spacing between section items messed up 2026-04-04 20:59:30 +02:00
Amruth Pillai 623c5f6f81 Downgrade Cosign installer version to v3 2026-04-04 12:53:26 +02:00
Amruth Pillai bcbe70d231 📦 v5.0.16 - https://docs.rxresu.me/changelog 2026-04-04 12:31:24 +02:00
Amruth Pillai 8b52b9d8fc update translations 2026-04-04 12:29:10 +02:00
Amruth Pillai 4ecc66d081 Update title/metadata of generated PDF (#2863) 2026-04-04 12:28:32 +02:00
Amruth Pillai 10d58175f1 refactor: update layout of resume items for better alignment and spacing 2026-04-04 12:21:05 +02:00
Amruth Pillai 923f5f6173 fixes #2733: Bug where date range is displayed on separate line (#2862) 2026-04-04 12:03:09 +02:00
Amruth Pillai 9332e1e3ff chore: update GitHub Actions workflows to use Node 24 and upgrade action versions 2026-04-02 00:28:36 +02:00
AaronJoel Dev 77f31fa127 fix: prevent desktop horizontal overflow in home hero (#2854) 2026-04-02 00:16:16 +02:00
Amruth Pillai 4fd43657dc 📦 v5.0.15 - https://docs.rxresu.me/changelog 2026-04-02 00:14:54 +02:00
Aman Gupta d9a24448e8 fix: refactor useCSSVariables to ensure valid highest font weights (#2852) 2026-03-31 22:41:24 +02:00
Amruth Pillai 69ff78b656 Sync Translations from Crowdin (#2848)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (English, United Kingdom)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-03-29 23:34:21 +02:00
Amruth Pillai 0794b5c955 update dependencies 2026-03-29 23:09:25 +02:00
Amruth Pillai 5c986cc68d Sync Translations from Crowdin (#2838)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (English, United Kingdom)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]
2026-03-29 23:07:48 +02:00
autofix-ci[bot] 688c002822 [autofix.ci] apply automated fixes 2026-03-24 10:58:09 +00:00
Amruth Pillai ced49d5314 Update Crowdin configuration file 2026-03-24 11:57:03 +01:00
Amruth Pillai 3653baad9b 📦 v5.0.14 - https://docs.rxresu.me/changelog 2026-03-24 11:22:45 +01:00
b4aaf9712f feat(mcp): add OAuth 2.1 for claude.ai MCP connector (#2829)
* feat(mcp): add OAuth 2.1 authentication for claude.ai MCP connector

Enable OAuth 2.1 (RFC 8414 + RFC 7591) for the MCP endpoint using
better-auth's MCP plugin. This allows claude.ai and other MCP clients
to authenticate via Dynamic Client Registration and Authorization Code
flow with PKCE, using the existing login page.

- Add `mcp()` plugin to better-auth config with login page redirect
- Add `.well-known/oauth-authorization-server` discovery endpoint
- Add `.well-known/oauth-protected-resource` metadata endpoint
- Update MCP handler to accept Bearer tokens via `getMcpSession`
- Retain `x-api-key` fallback for backward compatibility
- Return proper HTTP 401 + WWW-Authenticate header for unauthed requests
- Add `oauthApplication`, `oauthAccessToken`, `oauthConsent` tables

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(mcp): use typed AuthError and suppress noisy verifyApiKey throws

- Replace string-matching error detection with instanceof AuthError
- Wrap verifyApiKey in try-catch to avoid logging malformed key errors
- Move console.error below auth check so 401s don't pollute logs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(mcp): add database migration for OAuth tables

Creates oauth_application, oauth_access_token, and oauth_consent tables
required for MCP OAuth 2.1 Dynamic Client Registration flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(mcp): resolve OAuth Bearer token auth for oRPC tool calls

The oRPC context only checked session cookies and API keys, causing
MCP tool calls from OAuth clients (claude.ai) to fail with Unauthorized
even though the MCP endpoint itself authenticated successfully.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(mcp): look up user by userId from OAuth access token

getMcpSession returns OAuthAccessToken (with userId), not a session
object with a user property. Must query the user table by userId.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(mcp): migrate from deprecated mcp() plugin to @better-auth/oauth-provider

The better-auth MCP plugin is marked for deprecation in favor of the
OAuth Provider plugin. This refactors the entire OAuth 2.1 flow to use
@better-auth/oauth-provider with JWT-based token verification, replacing
the opaque token lookup via getMcpSession().

Key changes:
- Replace mcp() with jwt() + oauthProvider() in auth config
- Replace getMcpSession() with verifyAccessToken() (JWT/JWKS)
- Replace oauthApplication table with oauthClient (RFC 7591 compliant)
- Add oauthRefreshToken table and jwks table for JWT signing keys
- Extract shared authBaseUrl and verifyOAuthToken helper
- Hoist McpServer to module scope (avoid per-request reconstruction)
- Update .well-known discovery endpoints for OAuth Provider

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(mcp): resolve OAuth 2.1 flow for claude.ai MCP connector

Multiple fixes required to make the full MCP OAuth flow work with
claude.ai's implementation:

- Add RFC 8414 discovery route at /.well-known/oauth-authorization-server/api/auth
  (claude.ai appends the issuer path per spec)
- Add /auth/oauth server route to handle login/consent flow
  (generates auth codes directly, bypassing h3 cookie issues)
- Default token_endpoint_auth_method to "none" via onRequest plugin hook
  (claude.ai omits this field, causing confidential client rejection)
- Strip prompt=consent from authorize requests via onRequest hook
  (better-auth checks prompt before skipConsent, causing redirect loops)
- Add validAudiences for MCP resource URL
  (JWT aud claim contains the MCP URL, not the base URL)
- Disable CSRF check for cross-origin OAuth flows
- Log token endpoint errors for debugging
- Set skipConsent on OAuth clients via /auth/oauth route

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(mcp): harden OAuth security and enforce lock on delete

- Scope CSRF bypass to OAuth2 paths only instead of disabling globally
- Validate redirect_uri against registered client URIs (prevents code interception)
- Use pathname matching instead of fragile url.includes() for route guards
- Replace biased modulo code generation with crypto.randomBytes
- Enforce resume lock check on delete (previously silently ignored)
- Remove debug console.error logging of OAuth token response bodies
- Use Response.json() consistently for MCP 401 response

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update dependencies, refine ignore patterns, and enhance documentation

- Updated various dependencies in package.json and pnpm-lock.yaml for improved stability and features.
- Adjusted ignore patterns in knip.json to include specific component directories.
- Enhanced documentation for the MCP server, clarifying authentication methods and configuration options.
- Made minor adjustments to VSCode settings for better code organization.

* fix(mcp): resolve OAuth client registration and stale token handling

Claude.ai sends token_endpoint_auth_method: "client_secret_post" without
a client_secret during Dynamic Client Registration, causing Better Auth to
reject it as an unauthenticated confidential client. Force to "none" for
unauthenticated registrations.

Also catch JWKS verification errors (e.g. key rotation after redeployment)
so stale Bearer tokens return 401 instead of 200 with an error body,
allowing clients to re-initiate the OAuth flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* reiterate on tests

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-03-24 11:03:56 +01:00
Amruth Pillai e3274d7c95 New translations en-us.po (French) (#2834)
[ci skip]
2026-03-22 17:49:55 +01:00
Copilotamruthpillaicopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
a7a3d53dbd [WIP] Fix issue 2830 related to sidebar width slider (#2832)
* Initial plan

* fix: sidebar width slider not updating resume layout

Co-authored-by: amruthpillai <1134738+amruthpillai@users.noreply.github.com>
Agent-Logs-Url: https://github.com/amruthpillai/reactive-resume/sessions/55cb1943-2066-4871-8a12-0a0a4cb35fa6

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: amruthpillai <1134738+amruthpillai@users.noreply.github.com>
2026-03-21 08:24:42 +01:00
Amruth Pillai f8d776106f fixes #2826 2026-03-19 19:16:28 +01:00
Amruth Pillai e34f648455 remove input-otp component, upstream issues 2026-03-19 18:43:05 +01:00
Amruth Pillai f4e2d05f25 Merge branch 'main' of github.com:amruthpillai/reactive-resume 2026-03-19 12:55:46 +01:00
Amruth Pillai bbc17b8995 cleaner logging in dev and prod 2026-03-19 12:55:37 +01:00
Amruth Pillai a66bc13f4f Sync Translations from Crowdin (#2825)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (English, United Kingdom)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-03-19 10:23:34 +01:00
Amruth Pillai 7858efbd2b remove prepare script 2026-03-19 10:22:37 +01:00
Amruth Pillai 7da5e2c0c2 update schema.json and openapi/spec.json 2026-03-19 10:07:19 +01:00
Amruth Pillai 177c550a0c fix changelog formatting 2026-03-19 10:03:15 +01:00
Amruth Pillai 882725cabf 📦 v5.0.13 - https://docs.rxresu.me/changelog 2026-03-19 09:57:34 +01:00
Luka FagundesandAmruth Pillai 3e16586d7a feat(jobs): add job listings with AI-powered resume tailoring (#2788)
* feat: add job listings feature with JSearch API integration, resume tailoring, and per-user rate limiting

* feat(jobs): add search filters UI, filter helper functions with tests, and job_search_quota DB migration

* feat(jobs): add pagination with 30 results per page and prev/next navigation

* refactor(job-detail): Adjust sheet width and scroll area height

* feat(ai): Add resume tailoring feature and prompt

* refactor(ai): Revise tailoring prompts and schema for full skill rewrite

* feat(ai): Add reference tailoring and output sanitization

* feat(testing): Add Vitest testing framework

* fix: address PR review - atomic rate limiting, calendar-month quota, skill sync warning, gitignore routeTree.gen.ts

* feat(jobs): Add location filter to job listings

* feat(job-listings): Add DOCX document generation

* feat(job-listings): Enable search by location and on Enter key

* feat(job-listings): Split location filter into city, state, and country

* feat(jobs): Implement job search adapter and JSearch

* Update 'locale/' directory

* feat(resume): Simplify filename generation and add tests

* fix(JSearch): reduce JSearch API usage to 1 request per search to prevent quota exhaustion

* fix(JSearch): Displayed quota amounts on Job Search functionality and settings fixed to pull from RapidAPI/JSearch response

* fix(internal rate limit): Removed internal rate limit and .env.example addition, cloud based implementation handles.

* style(job-filters): Adjust layout of switch filters

* fix(typecheck): Fixed typecheck issues introduced to sync with origin

* feat(jobs): Enhance tailor dialog with apply link and tags

* feat(locale files): updated locale files with the latest build

* feat(jobs): Add job search provider and integrate testing functionality

- Introduced `createJobSearchProvider` function to instantiate a JSearchProvider.
- Enhanced job search provider with methods for searching jobs, retrieving job details, and testing connection.
- Updated `vite.config.ts` to include new testing configurations and plugins.
- Added new dependencies in `package.json` for testing and document generation.
- Removed obsolete `vitest.config.ts` file.
- Improved job search provider tests for better coverage and reliability.

* refactor: Update job search routes and remove obsolete test configurations

- Removed the test configuration from `vite.config.ts`.
- Updated localization files to reflect changes in job search routes, renaming references from `jobs` to `job-search` across multiple languages.
- Adjusted autofix workflow to run formatting without the `--fix` flag for better control over code style adjustments.

* chore: Update dependencies and improve animation performance

- Added `jsdom` as a new dependency in `package.json`.
- Updated `vite-plus` and `vitest` to the latest versions for better compatibility.
- Enhanced animation components with `willChange` styles to optimize rendering performance.
- Adjusted various UI components to improve responsiveness and visual effects.
- Removed obsolete job details functionality from the job search provider and related tests.

* chore(locales): Update localization files for job search improvements

- Modified job search related strings to remove references to "this month" for a more concise format.
- Updated file references in localization entries to reflect changes in the job search component structure.
- Added new strings for API usage, quota remaining, and job fetching error messages across multiple languages.
- Removed obsolete "Monthly Usage" string from localization files.

* chore(dependencies): Update @typescript/native-preview to version 7.0.0-dev.20260319.1

---------

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-03-19 09:48:02 +01:00
Amruth Pillai 56a1838315 update routeTree.gen.ts, ignore files 2026-03-18 22:11:37 +01:00
Amruth Pillai 2d76cc5cfb update autofix 2026-03-18 22:08:12 +01:00
Amruth Pillai 192880e416 use vite+ 2026-03-18 22:03:24 +01:00
Amruth Pillai d1dac8aeca Sync Translations from Crowdin (#2824)
* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (English, United Kingdom)
[ci skip]

* New translations en-us.po (French)
[ci skip]
2026-03-18 21:37:19 +01:00
Héphaïsto f13093249d Update French translation for 'Volunteer' to 'Bénévolat' (#2823)
Bénévole means The Volunteer (The person doing the action)
Bénévolat means actions made by volunteers so it is more adequat
2026-03-18 18:46:42 +01:00
Amruth PillaiCopilot Autofix powered by AIautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
99c602e3c7 Migrate from Biome to Oxlint/Oxfmt (#2822)
* Migrate from Biome to Oxlint/Oxfmt

* pin version of autofix

* set version of autofix

* pin version of autofix

* [autofix.ci] apply automated fixes

* better comments, test formatter

* [autofix.ci] apply automated fixes

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-18 14:59:05 +01:00
Amruth PillaiandCopilot Autofix powered by AI 040755bec9 Sync Translations from Crowdin (#2820)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (English, United Kingdom)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-18 11:56:42 +01:00
Amruth Pillai 1063680774 update translations 2026-03-18 11:04:00 +01:00
Amruth Pillai 1f8644bb54 add slovenian locale 2026-03-18 10:45:04 +01:00
Amruth Pillai 1d7c4b2615 update dependencies, fix type issues in auth, add migrations for missing indexes 2026-03-18 10:42:08 +01:00
Amruth Pillai d8ffd00fa6 update translations 2026-03-18 09:54:10 +01:00
Amruth Pillai f431c0fd89 language updates 2026-03-17 23:52:09 +01:00
Amruth Pillai 571a1c1efe use rtl friendly classes 2026-03-17 23:50:52 +01:00
Amruth Pillai 547afaa18f remove dead code 2026-03-17 23:50:04 +01:00
Amruth Pillai 7789c39fe3 better changelog 2026-03-17 23:48:14 +01:00
Amruth Pillai bfb2e8bb7e update changelog 2026-03-17 23:45:33 +01:00
Amruth Pillai 189290e093 consistent imports 2026-03-17 23:42:35 +01:00
Martin Joneš 7b541f3567 Resolve chromedp hostname to IP (#2811) 2026-03-17 23:42:04 +01:00
Amruth Pillai 5cd16a62d9 v5.0.12 (#2814)
* refactor to @base-ui/react

* fix all

* fixes to accordion

* more updates

* switch to chat/completions api from openai

* update version to v5.0.12
2026-03-17 23:38:06 +01:00
Amruth PillaiandCopilot Autofix powered by AI 89beb43ea2 Sync Translations from Crowdin (#2810)
* New translations en-us.po (English, United Kingdom)
[ci skip]

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-17 16:03:32 +01:00
Amruth Pillai 55757857bd Sync Translations from Crowdin (#2809)
* New translations en-us.po (English, United Kingdom)
[ci skip]

* New translations en-us.po (English, United Kingdom)
[ci skip]
2026-03-17 15:49:57 +01:00
Amruth Pillai 584444c1fc New translations en-us.po (English, United Kingdom) (#2808)
[ci skip]
2026-03-17 12:38:50 +01:00
fb61bb4a63 fix: resolve multi-page PDF crashes and Gemini API ingestion errors (#2781)
* fix: resolve multi-page PDF crashes and Gemini API ingestion errors

* fix type errors

* refactor: address PR review feedback and prevent call stack recursion in regex payload scanner

---------

Co-authored-by: Ofir <ofir@example.com>
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-03-16 23:08:40 +01:00
Yeung Lihan ea8fd838d9 feat(import): normalize missing layout sections for reactive resume json (#2799)
* feat(import): normalize missing layout sections for reactive resume json

* chore: add comments
2026-03-16 23:08:21 +01:00
Franco CarraraandFranco Carrara a3c58b0068 add or statement so logged users can see public resumes (#2801)
Co-authored-by: Franco Carrara <franco.carrara@crombie.dev>
2026-03-13 04:20:35 +01:00
Amruth Pillai e0e8879caf New translations en-us.po (German) (#2800)
[ci skip]
2026-03-12 20:12:47 +01:00
Yao Changyi feab19913b feat: Allow sidebar button list to scroll internally on overflow (#2791) 2026-03-10 22:58:56 +01:00
Yao Changyi afbe56af0d fix: Fix unnecessary scrollbar appearing on the right sidebar (#2792) 2026-03-10 22:58:21 +01:00
Amruth PillaiandCopilot d22ab8202c Sync Translations from Crowdin (#2797)
* New translations en-us.po (French)
[ci skip]

* Update locales/fr-FR.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update locales/fr-FR.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update locales/fr-FR.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-10 22:57:16 +01:00
Amruth Pillai f4b6db222c update dependencies 2026-03-06 12:11:22 +01:00
Amruth Pillai 44177c0d1b Sync Translations from Crowdin (#2779)
* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-03-06 10:30:11 +01:00
Amruth Pillai 1d59ea3bd0 fix migration 2026-03-05 11:59:14 +01:00
TheDuke427androot 5e9ae64b2b fix(experience): remove bold from role titles and tighten role progression spacing (#2777)
Co-authored-by: root <root@reactive-resume-dev.one.one.one.one>
2026-03-05 10:13:59 +01:00
Amruth Pillai 46392d9dfc fixes #2774 2026-03-05 10:10:55 +01:00
Amruth Pillai 6734da4bee add translations for role progression, fixes #2775 2026-03-05 09:51:07 +01:00
Amruth Pillai 27edc963ce 📦 v5.0.11 - https://docs.rxresu.me/changelog 2026-03-04 23:06:23 +01:00
4b46bda4e6 feat(experience): add role progression to show career advancement within a company (#2761)
* feat(experience): add role progression support for career advancement

* fix(experience): remove indent and border from role progression items

* refactor(experience): enhance role progression UI and functionality

- Updated the ExperienceItem component to improve role display and styling.
- Refactored the CreateExperienceDialog and UpdateExperienceDialog to support role reordering using drag-and-drop.
- Added role handling in JSON and ReactiveResume importers.
- Enhanced experience schema to include roles, ensuring better data structure for career progression.
- Improved overall user experience with clearer role management in the experience section.

---------

Co-authored-by: root <root@reactive-resume-dev.one.one.one.one>
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-03-04 21:34:37 +01:00
François Martin df81d0342f fix(printer): make PDF margins match resume background color (#2770)
* fix(printer): match PDF margins to resume background color

* fix(printer): preserve vertical margins when content wraps pages
2026-03-04 20:38:02 +01:00
Amruth Pillai 4825eed22c New translations en-us.po (German) (#2763)
[ci skip]
2026-03-04 20:33:21 +01:00
Amruth Pillai b0711351f7 update dependencies 2026-03-04 20:32:56 +01:00
Amruth PillaiandCursor Agent b7e4c86f4e Project quality audit (#2758)
* Harden security, health checks, and dependency hygiene

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* Finalize health and storage hardening adjustments

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* remove use of [REDACTED]

* update dependencies

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-02-28 01:14:02 +01:00
Amruth PillaiandCopilot c25c068d20 Sync Translations from Crowdin (#2756)
* New translations en-us.po (Indonesian)
[ci skip]

* Update locales/id-ID.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-28 01:06:15 +01:00
Amruth PillaiandCursor Agent d217d5dc4f Add AGENTS.md with Cursor Cloud development setup instructions (#2757)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-02-27 15:18:14 +01:00
Amruth Pillai 1ed80140b5 fix typescript error 2026-02-26 22:52:38 +01:00
Amruth Pillai 28ae7714c8 - fixes #2693, fixes #2716 2026-02-26 22:50:34 +01:00
Amruth Pillai 9d70bc4fd3 - fixes #2707 2026-02-26 22:44:46 +01:00
Amruth Pillai e5a51013c1 Sync Translations from Crowdin (#2746)
* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]
2026-02-26 22:39:26 +01:00
Amruth Pillai eeaac9a86f fixes #2727 2026-02-26 22:39:05 +01:00
Amruth Pillai 269dbc600f 📦 v5.0.10 · Changelog: https://docs.rxresu.me/changelog 2026-02-24 10:55:58 +01:00
Amruth Pillai 9b29a44429 fix(get-section-component): display titles for summary-type custom sections (#2744) 2026-02-24 10:48:44 +01:00
YeungandAmruth Pillai e9fa161148 fix(ai): prevent Edge/password-manager autofill and save prompts in AI settings (#2719)
* fix(ai): prevent password autofill in AI settings

* fix(ai): avoid password manager prompts for API key fields

* fix(ai): disable autocomplete for AI settings inputs

* update code style

---------

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-02-24 10:43:49 +01:00
Amruth Pillai 299d6d4878 fix(tailwindcss): replace start-[x]/end-[x] with inset-s-[x]/inset-e-[x] 2026-02-24 10:36:53 +01:00
Nyndow ea63ae6e72 fixing the pdf downloader in offline mode (#2743) 2026-02-24 10:14:06 +01:00
Kyle Tse 4d50cd9b71 fix: bold formatting not visible in rich text editor (#2731)
The editor_content CSS class used --page-body-font-weight-bold without
a fallback value. This variable is only injected in the resume preview
context (via use-css-variables.tsx), so in the editor UI the variable
was undefined, causing <strong> tags to render with no visible weight
change.

Adding a 'bold' fallback ensures bold text is correctly displayed in
the editor regardless of whether the CSS variable is set.

Fixes #2730
2026-02-24 10:11:35 +01:00
YeungandAmruth Pillai 8b3f3bcc35 fix(auth): avoid dropping session_token Set-Cookie on sign-in (#2718)
* fix credentials sign-in session cookie handling

* refactor(auth): rename originWith to withHostname

* refactor(auth): preserve localhost/127.0.0.1 sibling trust with LOCAL_ORIGINS

* update dependencies, update code style

---------

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-02-24 10:08:32 +01:00
Jacob f73a5117a1 fix: remove redundant resume- prefix from download filename, page spacing (#2709)
* fix: remove redundant resume- prefix from download filename

* fix: add spacing between pages in shared link view
2026-02-24 09:57:10 +01:00
YeungandAmruth Pillai 2d1e13b9b5 fix(auth): normalize autocomplete tokens for login and register (#2714)
Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-02-23 21:07:50 +01:00
Amruth Pillai b6c274eeb6 - fixes #2711
- fix improper re-ordering of chips
- update dependencies, translations
2026-02-23 21:02:35 +01:00
Amruth Pillai 4b78a7c9dd Sync Translations from Crowdin (#2712)
* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]
2026-02-23 19:39:05 +01:00
Amruth Pillai 87e2f2f391 add new feature flag FLAG_DISABLE_IMAGE_PROCESSING 2026-02-10 18:33:07 +01:00
Amruth Pillai f237c42093 replace discord invite link 2026-02-10 03:30:03 +01:00
Amruth Pillai a80f86e99e fix clipping of heading issue on lapras template 2026-02-10 03:23:41 +01:00
Amruth Pillai eb62ed99ce remove error-causing plugins in orpc 2026-02-10 01:43:11 +01:00
Amruth Pillai 45fc32323f Merge branch 'main' of github.com:amruthpillai/reactive-resume 2026-02-10 01:30:34 +01:00
Amruth Pillai f1d69da019 remove duplicate indexes on postgres, add index on created_at for user, resume 2026-02-10 01:30:32 +01:00
Amruth PillaiandClaude 9d131fdb99 Update CLAUDE.md with comprehensive codebase documentation (#2702)
Add details on ORPC procedure types, MCP server, all 13 resume templates,
Biome/TypeScript configuration, state management (Zundo), global providers,
Shadcn UI setup, build/deployment info, and expanded environment variables.

https://claude.ai/code/session_01NZ48uTqAAbNn3wAsSMsMGV

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 00:46:21 +01:00
Amruth Pillai 29ef6307e0 Sync Translations from Crowdin (#2701)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-02-10 00:18:14 +01:00
Amruth Pillai c3c771002f add computer modern fonts to the list of possible typography options 2026-02-10 00:12:04 +01:00
Amruth Pillai 554903b818 update spec.json 2026-02-09 23:20:27 +01:00
Amruth Pillai 6b71ecd7c6 Update dependencies and localization files
- Removed `@modelcontextprotocol/sdk` from ignoreDependencies in knip.json.
- Updated versions for several dependencies in package.json and pnpm-lock.yaml:
  - `@ai-sdk/google` to 3.0.23
  - `@ai-sdk/react` to 3.0.80
  - `@aws-sdk/client-s3` to 3.986.0
  - `ai` to 6.0.78
- Added new Afrikaans localization file and updated multiple existing localization files to remove passkey-related entries.
2026-02-09 23:10:45 +01:00
Amruth Pillai 833b8343ac building a better mcp server 2026-02-09 23:09:14 +01:00
Amruth Pillai 8e060890d3 remove ownership verification 2026-02-09 18:58:18 +01:00
Amruth Pillai abf0fc74e5 Add ownership verification 2026-02-09 18:57:58 +01:00
Amruth Pillai 6242c8c182 fix: temporarily disable passkeys functionality due to upstream issues (#2700)
* fix: temporarily disable passkeys functionality due to upstream issues

* remove sourcemaps from git
2026-02-09 14:52:39 +01:00
Amruth Pillai 15327d74d8 Sync Translations from Crowdin (#2697)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-02-09 14:48:54 +01:00
Amruth Pillai 90c34ca572 📦 v5.0.7 - Changelog: https://docs.rxresu.me/changelog (#2696) 2026-02-09 01:50:31 +01:00
Amruth Pillai 2b8fa9c7e8 fix: auto-select 2 font weights when picking a new font-family 2026-02-08 18:14:16 +01:00
Amruth Pillai 2f7aabcfe9 Update self-hosting guide link in README 2026-02-08 11:45:05 +01:00
Amruth Pillai ef6d054598 fixes #2612 2026-02-08 01:43:08 +01:00
Amruth Pillai 201d707aea fixes #2655 2026-02-08 01:39:58 +01:00
Amruth Pillai d8b0902ac9 fixes #2691 2026-02-08 01:39:24 +01:00
Amruth Pillai 01c75bd796 📦 v5.0.6 · Changelog: https://docs.rxresu.me/changelog 2026-02-08 01:18:41 +01:00
Amruth Pillai 0a609306a6 add error logging on server only 2026-02-08 01:16:38 +01:00
Amruth Pillai 5bdc6de862 update imports/exports 2026-02-08 00:28:28 +01:00
Amruth Pillai cc01fb9418 Feature: Implement Atomic Resume Patching API (#2692) 2026-02-08 00:16:11 +01:00
Arjun EarthpersonandAmruth Pillai 5e8e1349bc Return updated resume object from PUT /resume/{id} instead of void (#2688)
* implement PUT response

* Refactor resume router and service to use DTOs for input and output schemas

* define explicitly, the fields to be returned

---------

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-02-07 00:49:33 +01:00
Amruth Pillai ddbb71fb78 update dependencies 2026-02-06 23:07:37 +01:00
Amruth Pillai 3289453448 add .devcontainer 2026-02-06 19:15:56 +01:00
Amruth Pillai 611af8ee72 Add build badge and documentation link to README
Added a build badge for Ona and linked to documentation.
2026-02-06 19:05:40 +01:00
Amruth PillaiandCopilot 69b96a592d Sync Translations from Crowdin (#2686)
* New translations en-us.po (French)
[ci skip]

* Update locales/fr-FR.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-05 14:37:59 +01:00
Amruth Pillai 3151f6a9cc update dependencies 2026-02-03 22:55:22 +01:00
Amruth Pillai 726968288c fix lint errors 2026-02-02 17:37:15 +01:00
Arjun Earthperson ad086f337a update sample with cover letter and other existing fields (#2678) 2026-02-02 17:36:24 +01:00
Amruth Pillai 66d09820c3 rename service from "app" to "reactive_resume" 2026-02-02 13:27:14 +01:00
Amruth Pillai 5ec73e9234 fix no name returned in github 2026-02-02 13:03:49 +01:00
Amruth Pillai 17569d0658 add failure update to ai test status, when testing connection 2026-02-02 01:03:01 +01:00
Amruth Pillai 14ea464c0a add changelog, update README.md 2026-02-02 01:01:02 +01:00
Amruth Pillai da9a3c0b12 fixes #2663: validate AI output for test connection endpoint (#2674) 2026-02-02 00:43:31 +01:00
Abdul Alim f5a9ffb776 fix(layout): handle text overflow in sidebar/footer elements (#2672) 2026-02-01 22:17:30 +01:00
Amruth PillaiandCopilot 19181b79c8 Sync Translations from Crowdin (#2667)
* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* Update locales/it-IT.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-31 17:10:26 +01:00
Amruth Pillai 1509678578 fix auth error: "name is required" (#2668) 2026-01-31 17:09:14 +01:00
Amruth Pillai c4d5dd4a3c New translations en-us.po (Italian) (#2665)
[ci skip]
2026-01-31 15:42:43 +01:00
Amruth Pillai ca734ca547 Sync Translations from Crowdin (#2664)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]
2026-01-31 14:14:16 +01:00
Amruth PillaiandCursor 8d347f5162 Feature: Implement Embedding Links in Titles of all Section Items (#2662)
* feat: add options.showLinkInTitle to baseItemSchema

Add itemOptionsSchema with showLinkInTitle boolean property to control
whether the website URL is rendered as a hyperlink on the title instead
of a separate link at the bottom. The field is optional for backwards
compatibility with existing resumes.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: add hideLabelButton prop to URLInput

When hideLabelButton is true, the tag/label button is hidden from the
URL input. This is used when showLinkInTitle is enabled since the label
is not needed when the link is shown in the title.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: create LinkedTitle component for title-as-link rendering

Add a reusable component that conditionally renders the title as a
hyperlink when showLinkInTitle is true and a website URL is provided.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: add showLinkInTitle option to experience section

- Add Switch toggle in experience dialog for showLinkInTitle option
- Update URLInput to hide label button when showLinkInTitle is enabled
- Use LinkedTitle component in experience-item for conditional link rendering
- Hide bottom website link when showLinkInTitle is enabled

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: add showLinkInTitle option to all section items

- Update education, projects, awards, certifications, publications,
  volunteer, references, and profiles dialogs with Switch toggle
- Add LinkedTitle component usage in all corresponding item components
- Conditionally hide bottom website link when showLinkInTitle is enabled
- Add hideLabelButton prop to URLInput when showLinkInTitle is enabled

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: extract i18n strings for showLinkInTitle feature

Add "Show link in title" translation string to all locale catalogs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* update dependencies, fix an issue with glalie template and non-clickable links, fix better-auth type error

* remove unused export

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-01-31 12:16:23 +01:00
Amruth Pillai 4d368ab6f6 Sync Translations from Crowdin (#2660)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]
2026-01-31 11:09:44 +01:00
Amruth Pillai cabacdc44b Bump version from 5.0.4 to 5.0.5 2026-01-31 03:18:10 +01:00
Amruth Pillai 71dac2021d Feature: Implement Cover Letters as a custom section type (#2659) 2026-01-31 03:17:20 +01:00
Amruth Pillai a8d8d0e340 Feature: Implement full-screen mode for rich text editor (#2658) 2026-01-31 02:29:34 +01:00
Amruth Pillai 97274d1c80 Sync Translations from Crowdin (#2656)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]
2026-01-31 02:27:24 +01:00
Amruth Pillai aa12fcbd36 Feature: Implement a new custom section type: summary (#2657)
* feat: add summaryItemSchema for custom summary section type

* feat: add CreateSummaryItemDialog and UpdateSummaryItemDialog

* feat: register summary item dialog types in store

* feat: route summary item dialogs in manager

* feat: add SummaryItem render component

* feat: handle summary type in renderItemByType and hide title for summary sections

* feat: handle summary type in sidebar helpers

* feat: add summary to custom section type options

* fix: update type definitions to support CustomSectionType for summary sections

* chore: extract new i18n strings for summary section

* style: apply biome formatting fixes

* chore: remove TODO.md file containing outdated feature specifications
2026-01-31 01:53:27 +01:00
Amruth Pillai 3d1c2d1fb6 Feature: Create a new useFormBlocker hook to block the user from closing a dialog or navigating away from a page if the form is dirty (#2654)
* feat: add useFormBlocker hook for dialog dirty state protection

* feat: add useFormBlocker hook for dialog dirty state protection

- Create useFormBlocker hook that blocks dialog closing when forms have unsaved changes
- Use onPointerDownOutside and onEscapeKeyDown to intercept close attempts
- Show confirmation dialog with Leave/Stay options using useConfirm
- Integrate with CreateResumeDialog, UpdateResumeDialog, and DuplicateResumeDialog
- All strings are translatable via Lingui

* Feature: Create a new `useFormBlocker` hook to block the user from closing a dialog or navigating away from a page if the form is dirty.
2026-01-31 01:13:38 +01:00
Amruth Pillai f6fcbdcad0 Sync Translations from Crowdin (#2640)
* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]
2026-01-29 14:20:16 +01:00
Amruth PillaiandCopilot 30e6ba0809 Sync Translations from Crowdin (#2636)
* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Slovenian)
[ci skip]

* Update locales/uk-UA.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-28 22:11:26 +01:00
Tom 3cb0fc9f30 fix: remove empty keywords spacing in interests items (#2631)
Only render keywords fields when they contain values
2026-01-28 21:06:12 +01:00
Amruth PillaiandCopilot 5f578c3327 Sync Translations from Crowdin (#2634)
* New translations en-us.po (Ukrainian)
[ci skip]

* Update locales/uk-UA.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-28 21:05:43 +01:00
Amruth Pillai e56402058a Sync Translations from Crowdin (#2630)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-01-28 12:06:16 +01:00
Amruth Pillai 19ae21e797 📦 v5.0.4 - Changelog: https://docs.rxresu.me/changelog 2026-01-28 11:45:58 +01:00
Amruth Pillai b89a31d4ae update translation sources 2026-01-28 11:42:38 +01:00
Fynn FischbachandAmruth Pillai 07e06a6ed4 feat(builder): arrange sidebar builder depending on section type in template #2564 (#2603)
* feat: introduce template sidebar type

* feat: align sidebar builder depending on template alignment

* revert: keep full width toggle for now until we merge SortableLayoutItem on template change.

* fix: typo

* use string literals instead of enum, modify logic for layout display slightly

---------

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-01-28 11:37:44 +01:00
Amruth Pillai 89102d6612 Bring back Undo/Redo functionality in the resume builder (#2629) 2026-01-28 11:20:11 +01:00
Amruth PillaiandCopilot feda173b3b Sync Translations from Crowdin (#2628)
* New translations en-us.po (Swedish)
[ci skip]

* Update locales/sv-SE.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update locales/sv-SE.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update locales/sv-SE.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-28 10:44:44 +01:00
Amruth PillaiandCopilot 02f812ce96 Sync Translations from Crowdin (#2625)
* New translations en-us.po (French)
[ci skip]

* Update locales/fr-FR.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-27 20:59:56 +01:00
Fynn Fischbach 7250bed701 Fix/#2607 remove empty proficiency spacing (#2626)
* fix: remove empty proficiency and keywords spacing in skills items

Only render proficiency and keywords fields when they contain values,
preventing empty inline-block elements from reserving unwanted space
in templates like Pikachu.

Fixes #2607

* style: biome check --write
2026-01-27 20:59:40 +01:00
Amruth PillaiandCopilot 2b11b1a234 Sync Translations from Crowdin (#2623)
* New translations en-us.po (French)
[ci skip]

* Update locales/fr-FR.po

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-27 17:10:57 +01:00
Amruth PillaiandCursor Agent 18e8aadf18 Fix GitHub OAuth login for migrated users (#2620)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-01-27 13:03:09 +01:00
G 4840a292df Fixed trailing Git Merge text (#2619)
updated French locale to remove failed gitmerge chars
2026-01-27 12:39:53 +01:00
Amruth Pillai 76ca1995ca New translations en-us.po (Portuguese, Brazilian) (#2616)
[ci skip]
2026-01-27 01:45:52 +01:00
Amruth Pillai 0f333b1f24 another attempt to improve printer service communication 2026-01-26 20:37:27 +01:00
Amruth Pillai 1f8eaa423f Merge branch 'main' of github.com:amruthpillai/reactive-resume 2026-01-26 19:36:52 +01:00
Amruth Pillai 4e4d3670a2 desperate attempts to reduce chrome usage 2026-01-26 19:36:50 +01:00
Amruth Pillai cd9a6a80e3 New translations en-us.po (Persian) (#2602)
[ci skip]
2026-01-26 14:57:51 +01:00
Amruth Pillai 429618d5f8 fixes #2542, fixes #2573 2026-01-26 12:38:37 +01:00
Amruth Pillai 1e814a77cc Refactor Pikachu template layout to conditionally render header and page picture based on isFirstPage property 2026-01-26 11:19:08 +01:00
Amruth Pillai 41b0c57725 fix pikachu template to respect the fullWidth property 2026-01-26 11:16:05 +01:00
Amruth Pillai 470822f4a9 Update package dependencies and fix README link for self-hosting guide 2026-01-26 11:11:45 +01:00
Amruth Pillai 946bf9ec38 - fixes #2598 2026-01-26 06:38:59 +01:00
Amruth Pillai 49585940f7 Sync Translations from Crowdin (#2597)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-01-26 00:11:24 +01:00
Amruth Pillai 9257d62216 update links to pdf examples 2026-01-25 23:44:45 +01:00
Amruth Pillai 3a9d2e7652 New Feature: Free-Form Page Formats for PDFs (#2595) 2026-01-25 23:39:16 +01:00
Amruth Pillai 4b2e3c0ded Sync Translations from Crowdin (#2594)
* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]
2026-01-25 22:36:03 +01:00
Amruth Pillai 6978df4c3c fix a lot of the templates 2026-01-25 22:28:06 +01:00
Amruth Pillai 1f13189ec3 Merge branch 'main' of github.com:amruthpillai/reactive-resume 2026-01-25 22:06:15 +01:00
Amruth Pillai c08e8081fe remove dead code, update screenshots, add PWA support 2026-01-25 22:06:12 +01:00
Amruth Pillai d8c9b5a936 New translations en-us.po (Afrikaans) (#2592)
[ci skip]
2026-01-25 20:37:15 +01:00
Amruth Pillai fa823e1296 Merge branch 'main' of github.com:amruthpillai/reactive-resume 2026-01-25 19:41:43 +01:00
Amruth Pillai de89ab957b 📦 v5.0.3 - Changelog: https://docs.rxresu.me/changelog 2026-01-25 19:41:32 +01:00
Amruth Pillai 96920495d0 Sync Translations from Crowdin (#2590)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-01-25 19:35:38 +01:00
Amruth Pillai 92044de6b8 more chip input fixes 2026-01-25 19:35:20 +01:00
Amruth Pillai 8e8ef300ec fix #2585 - allow for re-ordering keywords, editing keywords in-place and deleting keywords (#2591) 2026-01-25 19:23:15 +01:00
Amruth Pillai 982220430e fix #2587 - allow for customizable endpoints for all AI providers (#2589) 2026-01-25 18:29:36 +01:00
IbrahimandAmruth Pillai 3f55c24e36 Improved the Right to Left Direction implementation for relevant languages. (#2583)
* Added support for right to left direction of bullet points in the page render and text editor

* Added right to left direction support by adding a toggle button in the layout and enhancing the css element of the page render to support it without affecting the default left to right direction

* Moved the Right to Life Direction Toggle feature to be integrated with the Languages section using locale

* change all occurrances of pl, pr, ml, mr, left, right to start/end equivalents

---------

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>
2026-01-25 18:18:20 +01:00
Amruth Pillai 0c65612368 - an assortment of bugfixes and improvements
- remove line numbers from generated locale files
- add .gitattributes to not display diffs of .po files
2026-01-25 17:49:23 +01:00
Amruth Pillai 3071b7dd37 Sync Translations from Crowdin (#2582)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-01-25 08:43:44 +01:00
Amruth Pillai 5daac24e73 Update package dependencies and synchronize translations
- Updated @tanstack/react-router and related packages to version 1.157.5 in package.json.
- Adjusted pnpm-lock.yaml to reflect the updated package versions.
- Modified localization files to update the "Last Updated" message reference and the resume deletion success message across multiple languages.
- Removed obsolete components related to resume cards and creation from the dashboard.
2026-01-25 03:15:19 +01:00
Amruth Pillai bcd2828305 update intro timelapse video landing page 2026-01-25 01:05:05 +01:00
Amruth Pillai b5f4e9af46 increase screenshot ttl to outdated resumes 2026-01-25 00:27:58 +01:00
Amruth Pillai 92f6a6a16b Sync Translations from Crowdin (#2576)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* update translations

* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-01-24 23:43:08 +01:00
Amruth Pillai 019a20d027 rename agent skill name 2026-01-24 23:21:55 +01:00
Amruth Pillai 1378feaf6a add additional launch args to browser 2026-01-24 23:19:58 +01:00
Amruth Pillai 22221e6fae add additional launch args to browser 2026-01-24 23:17:46 +01:00
Amruth Pillai d773ff5391 fix: add print:hidden to page decorators 2026-01-24 23:05:12 +01:00
Amruth Pillai be84f0cca6 📦 v5.0.2 · Changelog: https://docs.rxresu.me/changelog 2026-01-24 23:00:54 +01:00
Amruth Pillai 1419c16d04 add CLAUDE.md 2026-01-24 20:05:33 +01:00
Amruth Pillai 89f209014e fix issue with irregular heights of PDFs on resumes with sidebar backgrounds 2026-01-24 17:30:38 +01:00
Amruth Pillai 21aec46763 updates to printer, added changelog entry, restored deploy script in CI 2026-01-24 16:58:14 +01:00
Amruth Pillai 333b5e50c4 remove "-r require-metadata" from dockerfile 2026-01-24 14:18:37 +01:00
Amruth Pillai e94550b7b2 update product hunt launch date 2026-01-24 13:29:06 +01:00
Amruth Pillai dcdf8398da update version 2026-01-24 11:07:25 +01:00
Amruth Pillai 503f610ff6 Merge branch 'main' of github.com:amruthpillai/reactive-resume 2026-01-24 10:43:17 +01:00
Amruth Pillai c875cc858d Update .env.example with clearer instructions for PRINTER_APP_URL, remove pdf-lib dependency from package.json, and adjust translations for alignment and zoom features across multiple locales. Improve template layout consistency in various components. 2026-01-24 10:43:12 +01:00
Amruth Pillai 403384944c Sync Translations from Crowdin (#2570)
* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-01-24 09:05:20 +01:00
Amruth Pillai 4e73a81d4b - fixes #2562, add better error messages for duplicate resume slugs
- improvements made to ditgar template
- general improvements to all templates with backgrounds
- update dependencies and translations
- improved print function that handles single page and multi page resumes
2026-01-23 23:31:24 +01:00
Amruth Pillai ed74fb67f2 - fixes #2565
- adds pages for a variety of guides
- add images to the many of the guides and docs pages
2026-01-23 14:18:48 +01:00
Amruth Pillai 895af548a0 update email template 2026-01-23 10:24:45 +01:00
Amruth Pillai a32450ab22 add community spotlight page to the docs 2026-01-23 10:18:04 +01:00
Amruth Pillai a4fd7f8452 update key order 2026-01-23 09:30:17 +01:00
Amruth Pillai 8214f2a910 normalize section items with consistent css classes 2026-01-23 09:28:05 +01:00
Divyanshu Patil 06d54a9060 fix: username not allowing hyphens (#2558) 2026-01-23 08:31:43 +01:00
Amruth Pillai d801effbce Sync Translations from Crowdin (#2557)
* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]

* New translations en-us.po (Romanian)
[ci skip]

* New translations en-us.po (French)
[ci skip]

* New translations en-us.po (Spanish)
[ci skip]

* New translations en-us.po (Afrikaans)
[ci skip]

* New translations en-us.po (Arabic)
[ci skip]

* New translations en-us.po (Bulgarian)
[ci skip]

* New translations en-us.po (Catalan)
[ci skip]

* New translations en-us.po (Czech)
[ci skip]

* New translations en-us.po (Danish)
[ci skip]

* New translations en-us.po (German)
[ci skip]

* New translations en-us.po (Greek)
[ci skip]

* New translations en-us.po (Finnish)
[ci skip]

* New translations en-us.po (Hebrew)
[ci skip]

* New translations en-us.po (Hungarian)
[ci skip]

* New translations en-us.po (Italian)
[ci skip]

* New translations en-us.po (Japanese)
[ci skip]

* New translations en-us.po (Korean)
[ci skip]

* New translations en-us.po (Lithuanian)
[ci skip]

* New translations en-us.po (Dutch)
[ci skip]

* New translations en-us.po (Norwegian)
[ci skip]

* New translations en-us.po (Polish)
[ci skip]

* New translations en-us.po (Portuguese)
[ci skip]

* New translations en-us.po (Russian)
[ci skip]

* New translations en-us.po (Slovak)
[ci skip]

* New translations en-us.po (Albanian)
[ci skip]

* New translations en-us.po (Serbian (Cyrillic))
[ci skip]

* New translations en-us.po (Swedish)
[ci skip]

* New translations en-us.po (Turkish)
[ci skip]

* New translations en-us.po (Ukrainian)
[ci skip]

* New translations en-us.po (Chinese Simplified)
[ci skip]

* New translations en-us.po (Chinese Traditional)
[ci skip]

* New translations en-us.po (Vietnamese)
[ci skip]

* New translations en-us.po (Portuguese, Brazilian)
[ci skip]

* New translations en-us.po (Indonesian)
[ci skip]

* New translations en-us.po (Persian)
[ci skip]

* New translations en-us.po (Khmer)
[ci skip]

* New translations en-us.po (Tamil)
[ci skip]

* New translations en-us.po (Bengali)
[ci skip]

* New translations en-us.po (Marathi)
[ci skip]

* New translations en-us.po (Thai)
[ci skip]

* New translations en-us.po (Latvian)
[ci skip]

* New translations en-us.po (Azerbaijani)
[ci skip]

* New translations en-us.po (Hindi)
[ci skip]

* New translations en-us.po (Malay)
[ci skip]

* New translations en-us.po (Telugu)
[ci skip]

* New translations en-us.po (Malayalam)
[ci skip]

* New translations en-us.po (Uzbek)
[ci skip]

* New translations en-us.po (Kannada)
[ci skip]

* New translations en-us.po (Odia)
[ci skip]

* New translations en-us.po (Amharic)
[ci skip]

* New translations en-us.po (Nepali)
[ci skip]
2026-01-23 02:53:50 +01:00
Amruth Pillai 6658412f8b fixes #2539, show all possible font weight options for local fonts or unknown fontFamily 2026-01-23 02:04:11 +01:00
Amruth Pillai 11cbeb27f8 fixes #2552, implement FLAG_DISABLE_SIGNUPS and FLAG_DISABLE_EMAIL_AUTH 2026-01-23 01:45:42 +01:00
Amruth Pillai 6db9fee823 Merge pull request #2556 from VinhLe1410/main
chore: clean up Goternberg references
2026-01-23 01:08:59 +01:00
Amruth Pillai 35e2daa807 lot of bugfixes, better migration script 2026-01-23 01:07:52 +01:00
Phuc Vinh Le 0b61ddda2d chore: remove Goternberg references in Vite env file 2026-01-23 07:18:49 +11:00
Phuc Vinh Le 0045bbd785 fix: remove gotenberg reference in compose.yml file 2026-01-23 07:12:46 +11:00
Amruth Pillai a10954ed14 Merge branch 'main' of github.com:amruthpillai/reactive-resume 2026-01-22 15:46:11 +01:00
Amruth Pillai 0bc53b9c2a - simplify imports
- update translations
- convert image to base64 before sending to printer
- update development docs
2026-01-22 15:46:09 +01:00
Amruth Pillai 2aeed6c58f Add MIT License to the project 2026-01-21 23:44:48 +01:00
Amruth Pillai 36a9e27c93 Merge pull request #2547 from amruthpillai/l10n
Sync Translations from Crowdin
2026-01-21 23:43:23 +01:00
Amruth Pillai 36a0094631 Merge branch 'main' into l10n 2026-01-21 23:43:13 +01:00
Amruth Pillai 5d73998f82 add an alternative to browserless, for lightweight servers 2026-01-21 23:24:37 +01:00
Amruth Pillai 3cb6f763ca New translations en-us.po (Nepali)
[ci skip]
2026-01-21 23:04:53 +01:00
Amruth Pillai a438130784 New translations en-us.po (Amharic)
[ci skip]
2026-01-21 23:04:51 +01:00
Amruth Pillai c72d6205e0 New translations en-us.po (Odia)
[ci skip]
2026-01-21 23:04:50 +01:00
Amruth Pillai ce16f81dbf New translations en-us.po (Kannada)
[ci skip]
2026-01-21 23:04:49 +01:00
Amruth Pillai c786f58ab8 New translations en-us.po (Uzbek)
[ci skip]
2026-01-21 23:04:48 +01:00
Amruth Pillai ec19386317 New translations en-us.po (Malayalam)
[ci skip]
2026-01-21 23:04:47 +01:00
Amruth Pillai 5576184f1b New translations en-us.po (Telugu)
[ci skip]
2026-01-21 23:04:46 +01:00
Amruth Pillai ebb40664f2 New translations en-us.po (Malay)
[ci skip]
2026-01-21 23:04:44 +01:00
Amruth Pillai e5ad94e620 New translations en-us.po (Hindi)
[ci skip]
2026-01-21 23:04:43 +01:00
Amruth Pillai e5934bf94b New translations en-us.po (Azerbaijani)
[ci skip]
2026-01-21 23:04:42 +01:00
Amruth Pillai 5cfd7e00bb New translations en-us.po (Latvian)
[ci skip]
2026-01-21 23:04:41 +01:00
Amruth Pillai 649bfefd06 New translations en-us.po (Thai)
[ci skip]
2026-01-21 23:04:40 +01:00
Amruth Pillai 0e96b9bfae New translations en-us.po (Marathi)
[ci skip]
2026-01-21 23:04:39 +01:00
Amruth Pillai 4b87ab6fe9 New translations en-us.po (Bengali)
[ci skip]
2026-01-21 23:04:37 +01:00
Amruth Pillai ff2986b3f8 New translations en-us.po (Tamil)
[ci skip]
2026-01-21 23:04:36 +01:00
Amruth Pillai 8d75537153 New translations en-us.po (Khmer)
[ci skip]
2026-01-21 23:04:35 +01:00
Amruth Pillai 8ffce2a264 New translations en-us.po (Persian)
[ci skip]
2026-01-21 23:04:34 +01:00
Amruth Pillai 083466202e New translations en-us.po (Indonesian)
[ci skip]
2026-01-21 23:04:33 +01:00
Amruth Pillai 7dff245b1a New translations en-us.po (Portuguese, Brazilian)
[ci skip]
2026-01-21 23:04:32 +01:00
Amruth Pillai 272f0795d1 New translations en-us.po (Vietnamese)
[ci skip]
2026-01-21 23:04:30 +01:00
Amruth Pillai 22ebb7b8eb New translations en-us.po (Chinese Traditional)
[ci skip]
2026-01-21 23:04:29 +01:00
Amruth Pillai f6ab720d73 New translations en-us.po (Chinese Simplified)
[ci skip]
2026-01-21 23:04:28 +01:00
Amruth Pillai a735580540 New translations en-us.po (Ukrainian)
[ci skip]
2026-01-21 23:04:27 +01:00
Amruth Pillai 3bcd480345 New translations en-us.po (Turkish)
[ci skip]
2026-01-21 23:04:26 +01:00
Amruth Pillai 63684ce9a0 New translations en-us.po (Swedish)
[ci skip]
2026-01-21 23:04:24 +01:00
Amruth Pillai fc4678ae98 New translations en-us.po (Serbian (Cyrillic))
[ci skip]
2026-01-21 23:04:23 +01:00
Amruth Pillai f87575958a New translations en-us.po (Albanian)
[ci skip]
2026-01-21 23:04:22 +01:00
Amruth Pillai 6b051dbf60 New translations en-us.po (Slovak)
[ci skip]
2026-01-21 23:04:20 +01:00
Amruth Pillai fb8917cf40 New translations en-us.po (Russian)
[ci skip]
2026-01-21 23:04:19 +01:00
Amruth Pillai 8c674fe510 New translations en-us.po (Portuguese)
[ci skip]
2026-01-21 23:04:18 +01:00
Amruth Pillai f5c4487bb9 New translations en-us.po (Polish)
[ci skip]
2026-01-21 23:04:17 +01:00
Amruth Pillai 588cee17fb New translations en-us.po (Norwegian)
[ci skip]
2026-01-21 23:04:16 +01:00
Amruth Pillai ea1ac92a56 New translations en-us.po (Dutch)
[ci skip]
2026-01-21 23:04:15 +01:00
Amruth Pillai 12c415e505 New translations en-us.po (Lithuanian)
[ci skip]
2026-01-21 23:04:14 +01:00
Amruth Pillai 2c292e3bad New translations en-us.po (Korean)
[ci skip]
2026-01-21 23:04:12 +01:00
Amruth Pillai dc3d3c2971 New translations en-us.po (Japanese)
[ci skip]
2026-01-21 23:04:11 +01:00
Amruth Pillai c86b049c92 New translations en-us.po (Italian)
[ci skip]
2026-01-21 23:04:10 +01:00
Amruth Pillai b0ca3ddfab New translations en-us.po (Hungarian)
[ci skip]
2026-01-21 23:04:09 +01:00
Amruth Pillai 59fc84d975 New translations en-us.po (Hebrew)
[ci skip]
2026-01-21 23:04:08 +01:00
Amruth Pillai 13f817d057 New translations en-us.po (Finnish)
[ci skip]
2026-01-21 23:04:07 +01:00
Amruth Pillai b50e11e4b4 New translations en-us.po (Greek)
[ci skip]
2026-01-21 23:04:05 +01:00
Amruth Pillai d56d834245 New translations en-us.po (German)
[ci skip]
2026-01-21 23:04:04 +01:00
Amruth Pillai 06d23ac98e New translations en-us.po (Danish)
[ci skip]
2026-01-21 23:04:03 +01:00
Amruth Pillai 6ec5a409d0 New translations en-us.po (Czech)
[ci skip]
2026-01-21 23:04:01 +01:00
Amruth Pillai 7fd0a66eac New translations en-us.po (Catalan)
[ci skip]
2026-01-21 23:04:00 +01:00
Amruth Pillai 52184112b1 New translations en-us.po (Bulgarian)
[ci skip]
2026-01-21 23:03:59 +01:00
Amruth Pillai 89473ac4e7 New translations en-us.po (Arabic)
[ci skip]
2026-01-21 23:03:58 +01:00
Amruth Pillai 2f66afdc87 New translations en-us.po (Afrikaans)
[ci skip]
2026-01-21 23:03:57 +01:00
Amruth Pillai 16cbad2028 New translations en-us.po (Spanish)
[ci skip]
2026-01-21 23:03:55 +01:00
Amruth Pillai 2f49075d89 New translations en-us.po (French)
[ci skip]
2026-01-21 23:03:54 +01:00
Amruth Pillai 8771f2716a New translations en-us.po (Romanian)
[ci skip]
2026-01-21 23:03:53 +01:00
Amruth Pillai 4d72a953dd fix for Reflect.getMetadata 2026-01-21 22:01:55 +01:00
Amruth Pillai b5ea68af5b New translations en-us.po (French)
[ci skip]
2026-01-21 21:57:12 +01:00
Amruth Pillai 499346e7ba one more for annotations 2026-01-21 21:55:10 +01:00
Amruth Pillai 81f4a3e148 try this 2026-01-21 21:45:42 +01:00
Amruth Pillai 7fd54c4259 try again 2026-01-21 21:42:41 +01:00
Amruth Pillai fda2d384e6 update docker-build for beta 2026-01-21 21:14:44 +01:00
Amruth Pillai 270ccf746c beta 2026-01-21 21:08:21 +01:00
Amruth Pillai 6b51d1bbaa New translations en-us.po (French)
[ci skip]
2026-01-21 20:47:24 +01:00
Amruth Pillai a0e17f0c27 New translations en-us.po (French)
[ci skip]
2026-01-21 19:12:04 +01:00
Amruth Pillai 70064be7de - Use browserless over gotenberg
- Implement functionality to move items between sections or pages
- Enhance custom sections to have a `type` property
- Update the v4 importer to account for custom sections
- Update healthcheck to be a simple curl command
- Update dependencies to latest
and a lot more changes
2026-01-21 18:49:54 +01:00
Amruth PillaiandCopilot 332286f9ce Update locales/fr-FR.po
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-21 17:57:20 +01:00
Amruth Pillai 7584412fcb New translations en-us.po (French)
[ci skip]
2026-01-21 17:17:03 +01:00
Amruth Pillai b3c342b029 change launch date 2026-01-21 05:51:13 +01:00
Amruth Pillai cf6db1a0ee Merge pull request #2536 from amruthpillai/l10n
Sync Translations from Crowdin
2026-01-21 05:04:13 +01:00
Amruth Pillai 2ac5c9137c fixes #2540 2026-01-21 05:03:30 +01:00
Amruth Pillai 8bafefe1b8 New translations en-us.po (Nepali)
[ci skip]
2026-01-20 20:50:23 +01:00
Amruth Pillai 5a42b776ff New translations en-us.po (Amharic)
[ci skip]
2026-01-20 20:50:22 +01:00
Amruth Pillai dfe53629bc New translations en-us.po (Odia)
[ci skip]
2026-01-20 20:50:21 +01:00
Amruth Pillai fc6690d047 New translations en-us.po (Kannada)
[ci skip]
2026-01-20 20:50:20 +01:00
Amruth Pillai b3904750b8 New translations en-us.po (Uzbek)
[ci skip]
2026-01-20 20:50:19 +01:00
Amruth Pillai 63ea01b219 New translations en-us.po (Malayalam)
[ci skip]
2026-01-20 20:50:18 +01:00
Amruth Pillai 4345f48dcc New translations en-us.po (Telugu)
[ci skip]
2026-01-20 20:50:17 +01:00
Amruth Pillai 7f8869649f New translations en-us.po (Malay)
[ci skip]
2026-01-20 20:50:16 +01:00
Amruth Pillai 06777e8285 New translations en-us.po (Hindi)
[ci skip]
2026-01-20 20:50:14 +01:00
Amruth Pillai 0907bddf75 New translations en-us.po (Azerbaijani)
[ci skip]
2026-01-20 20:50:13 +01:00
Amruth Pillai 8cf225a3e7 New translations en-us.po (Latvian)
[ci skip]
2026-01-20 20:50:12 +01:00
Amruth Pillai 71a931fdee New translations en-us.po (Thai)
[ci skip]
2026-01-20 20:50:11 +01:00
Amruth Pillai aa2109f4bd New translations en-us.po (Marathi)
[ci skip]
2026-01-20 20:50:10 +01:00
Amruth Pillai c2edf9651a New translations en-us.po (Bengali)
[ci skip]
2026-01-20 20:50:09 +01:00
Amruth Pillai 88e5c3e87e New translations en-us.po (Tamil)
[ci skip]
2026-01-20 20:50:08 +01:00
Amruth Pillai e2d593327a New translations en-us.po (Khmer)
[ci skip]
2026-01-20 20:50:07 +01:00
Amruth Pillai 104047f672 New translations en-us.po (Persian)
[ci skip]
2026-01-20 20:50:05 +01:00
Amruth Pillai 9c3faf1edf New translations en-us.po (Indonesian)
[ci skip]
2026-01-20 20:50:04 +01:00
Amruth Pillai 1dc5bf21e0 New translations en-us.po (Portuguese, Brazilian)
[ci skip]
2026-01-20 20:50:02 +01:00
Amruth Pillai 8bc4f3de84 New translations en-us.po (Vietnamese)
[ci skip]
2026-01-20 20:50:01 +01:00
Amruth Pillai 6af3b32302 New translations en-us.po (Chinese Traditional)
[ci skip]
2026-01-20 20:50:00 +01:00
Amruth Pillai dd517627c1 New translations en-us.po (Chinese Simplified)
[ci skip]
2026-01-20 20:49:59 +01:00
Amruth Pillai 05d5824131 New translations en-us.po (Ukrainian)
[ci skip]
2026-01-20 20:49:58 +01:00
Amruth Pillai 655138c0ea New translations en-us.po (Turkish)
[ci skip]
2026-01-20 20:49:57 +01:00
Amruth Pillai 7209eecaba New translations en-us.po (Swedish)
[ci skip]
2026-01-20 20:49:55 +01:00
Amruth Pillai 3d36849508 New translations en-us.po (Serbian (Cyrillic))
[ci skip]
2026-01-20 20:49:54 +01:00
Amruth Pillai 2e42146102 New translations en-us.po (Albanian)
[ci skip]
2026-01-20 20:49:53 +01:00
Amruth Pillai ab05f2533f New translations en-us.po (Slovak)
[ci skip]
2026-01-20 20:49:51 +01:00
Amruth Pillai 53f796aef7 New translations en-us.po (Russian)
[ci skip]
2026-01-20 20:49:50 +01:00
Amruth Pillai 09ea72cb2f New translations en-us.po (Portuguese)
[ci skip]
2026-01-20 20:49:49 +01:00
Amruth Pillai 84cc897fb4 New translations en-us.po (Polish)
[ci skip]
2026-01-20 20:49:47 +01:00
Amruth Pillai d3cc2b8011 New translations en-us.po (Norwegian)
[ci skip]
2026-01-20 20:49:46 +01:00
Amruth Pillai f4d56195c4 New translations en-us.po (Dutch)
[ci skip]
2026-01-20 20:49:45 +01:00
Amruth Pillai ce33a71a43 New translations en-us.po (Lithuanian)
[ci skip]
2026-01-20 20:49:44 +01:00
Amruth Pillai 90ae8511b5 New translations en-us.po (Korean)
[ci skip]
2026-01-20 20:49:43 +01:00
Amruth Pillai f41d53cf36 New translations en-us.po (Japanese)
[ci skip]
2026-01-20 20:49:42 +01:00
Amruth Pillai e16437aeed New translations en-us.po (Italian)
[ci skip]
2026-01-20 20:49:41 +01:00
Amruth Pillai c2d942d3f2 New translations en-us.po (Hungarian)
[ci skip]
2026-01-20 20:49:39 +01:00
Amruth Pillai cc5a90b3ca New translations en-us.po (Hebrew)
[ci skip]
2026-01-20 20:49:38 +01:00
Amruth Pillai 2942c5a329 New translations en-us.po (Finnish)
[ci skip]
2026-01-20 20:49:37 +01:00
Amruth Pillai d214ea8319 New translations en-us.po (Greek)
[ci skip]
2026-01-20 20:49:36 +01:00
Amruth Pillai 7a80b13db8 New translations en-us.po (German)
[ci skip]
2026-01-20 20:49:35 +01:00
Amruth Pillai d55e179890 New translations en-us.po (Danish)
[ci skip]
2026-01-20 20:49:34 +01:00
Amruth Pillai 33563a4cf8 New translations en-us.po (Czech)
[ci skip]
2026-01-20 20:49:32 +01:00
Amruth Pillai fe21523934 New translations en-us.po (Catalan)
[ci skip]
2026-01-20 20:49:31 +01:00
Amruth Pillai 9840613e0a New translations en-us.po (Bulgarian)
[ci skip]
2026-01-20 20:49:30 +01:00
Amruth Pillai 80c3e80dba New translations en-us.po (Arabic)
[ci skip]
2026-01-20 20:49:29 +01:00
Amruth Pillai c6ab0700b7 New translations en-us.po (Afrikaans)
[ci skip]
2026-01-20 20:49:28 +01:00
Amruth Pillai 6d23773569 New translations en-us.po (Spanish)
[ci skip]
2026-01-20 20:49:27 +01:00
Amruth Pillai f5bc16944f New translations en-us.po (French)
[ci skip]
2026-01-20 20:49:26 +01:00
Amruth Pillai 004b9bd8c4 New translations en-us.po (Romanian)
[ci skip]
2026-01-20 20:49:25 +01:00
Amruth Pillai 4b7fa5a303 run docker build only on tag release 2026-01-20 20:39:12 +01:00
Amruth Pillai 9efc9653a7 bring back warp 2026-01-20 20:37:51 +01:00
Amruth Pillai 0ff51a82ee fix flex width issue in pikachu 2026-01-20 20:34:21 +01:00
Amruth Pillai d874ea4f83 increase api rate limiter to 500 requests per day 2026-01-20 20:24:50 +01:00
Amruth Pillai 5688c97ee0 fixes #2530 2026-01-20 20:18:28 +01:00
Amruth Pillai 3cbf953ad2 fixes #2525 2026-01-20 19:59:54 +01:00
Amruth Pillai 4f61e921cd fixes #2526 2026-01-20 19:57:26 +01:00
Amruth Pillai f903e6099b fixes #2529 2026-01-20 19:50:33 +01:00
Amruth Pillai f3a6c0db6b fixes #2531 2026-01-20 19:40:25 +01:00
Amruth Pillai 5880078bfc fixes #2532 2026-01-20 19:38:13 +01:00
Amruth Pillai 6689232f7a New translations en-us.po (Spanish)
[ci skip]
2026-01-20 19:24:39 +01:00
Amruth Pillai 29cc5be9b3 New translations en-us.po (Chinese Simplified)
[ci skip]
2026-01-20 16:28:13 +01:00
Amruth Pillai 9dd0611ccc add sso documentation, fixes #2518 2026-01-20 14:20:13 +01:00
Amruth Pillai b0c8017839 update sitemaps 2026-01-20 13:30:09 +01:00
Amruth Pillai 891828af8e Merge pull request #2516 from amruthpillai/2514-bug-removing-the-whole-page-after-deleting-custom-section
fix: deleting a custom section deletes all items from the layout
2026-01-20 12:57:59 +01:00
Amruth Pillai 32466c758c fixes #2514 - deleting a custom section deletes all items from the layout 2026-01-20 12:55:57 +01:00
Amruth Pillai 3b11316982 New translations en-us.po (Chinese Simplified)
[ci skip]
2026-01-20 12:51:49 +01:00
Amruth Pillai b87e5dd023 add more guides on migration and self-hosting docker compose examples, change launch date for banner, update dependencies 2026-01-20 10:35:37 +01:00
Amruth Pillai 7e5597271b update naming convention of repository 2026-01-20 01:22:00 +01:00
Amruth Pillai 3d1334f7d9 add docker-hub-description.yml 2026-01-20 01:10:01 +01:00
Amruth Pillai 5f5c2e1a52 optimize images for faster loading, fix meta description tag 2026-01-20 01:03:02 +01:00
Amruth Pillai ce8d273c79 - skip running workflow on tag push
- remove ISSUE_AI_CHAT_BUILDER.md
2026-01-20 00:33:47 +01:00
655 changed files with 223307 additions and 119068 deletions
+10
View File
@@ -0,0 +1,10 @@
FROM mcr.microsoft.com/devcontainers/typescript-node:24
RUN corepack enable
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
EXPOSE 3000
+33
View File
@@ -0,0 +1,33 @@
{
"name": "Reactive Resume",
"service": "reactive_resume",
"dockerComposeFile": "docker-compose.yml",
"workspaceFolder": "/workspace",
"forwardPorts": [3000, 4000, 5432, 8333],
"portsAttributes": {
"3000": { "label": "Reactive Resume", "onAutoForward": "openBrowser" },
"4000": { "label": "Browserless (Printer)" },
"5432": { "label": "PostgreSQL" },
"8333": { "label": "SeaweedFS (S3)" }
},
"customizations": {
"vscode": {
"extensions": [
"oxc.oxc-vscode",
"bradlc.vscode-tailwindcss",
"lokalise.i18n-ally",
"typescriptteam.native-preview"
],
"settings": {
"editor.defaultFormatter": "oxc.oxc-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.oxc": "always"
}
}
}
},
"postCreateCommand": "corepack enable && pnpm install"
}
+95
View File
@@ -0,0 +1,95 @@
services:
reactive_resume:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspace:cached
command: sleep infinity
depends_on:
postgres:
condition: service_healthy
browserless:
condition: service_started
seaweedfs:
condition: service_healthy
seaweedfs_create_bucket:
condition: service_completed_successfully
environment:
TZ: Etc/UTC
APP_URL: http://localhost:3000
PRINTER_APP_URL: http://reactive_resume:3000
PRINTER_ENDPOINT: ws://browserless:3000?token=1234567890
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
AUTH_SECRET: change-me-to-a-secure-secret-key-in-production
S3_ACCESS_KEY_ID: seaweedfs
S3_SECRET_ACCESS_KEY: seaweedfs
S3_REGION: us-east-1
S3_ENDPOINT: http://seaweedfs:8333
S3_BUCKET: reactive-resume
S3_FORCE_PATH_STYLE: "true"
postgres:
image: postgres:latest
restart: unless-stopped
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- postgres_data:/var/lib/postgresql
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres", "-d", "postgres"]
start_period: 10s
interval: 30s
timeout: 10s
retries: 3
browserless:
image: ghcr.io/browserless/chromium:latest
restart: unless-stopped
environment:
QUEUED: "10"
HEALTH: "true"
CONCURRENT: "5"
TOKEN: "1234567890"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/pressure?token=1234567890"]
interval: 10s
timeout: 5s
retries: 10
seaweedfs:
image: chrislusf/seaweedfs:latest
restart: unless-stopped
command: server -s3 -filer -dir=/data -ip=0.0.0.0
environment:
AWS_ACCESS_KEY_ID: seaweedfs
AWS_SECRET_ACCESS_KEY: seaweedfs
volumes:
- seaweedfs_data:/data
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:8888"]
start_period: 10s
interval: 30s
timeout: 10s
retries: 3
seaweedfs_create_bucket:
image: quay.io/minio/mc:latest
restart: on-failure
entrypoint: >
/bin/sh -c "
until mc alias set seaweedfs http://seaweedfs:8333 seaweedfs seaweedfs; do
echo 'Waiting for SeaweedFS...';
sleep 2;
done;
mc mb seaweedfs/reactive-resume --ignore-existing;
"
depends_on:
seaweedfs:
condition: service_healthy
volumes:
postgres_data:
seaweedfs_data:
+25 -14
View File
@@ -3,21 +3,14 @@ TZ="Etc/UTC"
APP_URL="http://localhost:3000"
# Optional, uses APP_URL by default
# This can be set to a different URL (like http://host.docker.internal:3000 or http://{docker_service}:3000)
# to let the browser navigate to a non-public instance of Reactive Resume
# PLEASE READ: This should be set to an internal URL (like http://host.docker.internal:3000 or http://{docker_service}:3000)
# to let the browser navigate to a non-public instance of Reactive Resume.
# This is required when the printer service is running inside Docker, and cannot reach the app via the APP URL,
# which is usually when the APP_URL is localhost or a local network IP/hostname.
PRINTER_APP_URL="http://host.docker.internal:3000"
# Note: set this to `http://host.docker.internal:3000` if your `gotenberg` service is running on docker, but Reactive Resume is running outside of Docker.
# --- Printer ---
GOTENBERG_ENDPOINT="http://localhost:4000"
# Gotenberg Authentication (Optional)
# TIP: It's safest to avoid exposing your Gotenberg instance to the public internet; connect via a private Docker network instead.
# However, if Gotenberg needs to be hosted remotely from Reactive Resume, use these credentials to enable basic authentication for security.
# For setup details and security best practices, see: https://gotenberg.dev/docs/configuration#api:~:text=API%5FENABLE%5FBASIC%5FAUTH
# GOTENBERG_USERNAME=""
# GOTENBERG_PASSWORD=""
PRINTER_ENDPOINT="ws://localhost:4000?token=1234567890"
# --- Database (PostgreSQL) ---
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"
@@ -26,6 +19,9 @@ DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres"
# Generated using `openssl rand -hex 32`
AUTH_SECRET="change-me-to-a-secure-secret-key-in-production"
# Better Auth Dashboard (optional)
BETTER_AUTH_API_KEY=""
# Social Auth (Google, optional)
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""
@@ -34,7 +30,11 @@ GOOGLE_CLIENT_SECRET=""
GITHUB_CLIENT_ID=""
GITHUB_CLIENT_SECRET=""
# Custom OAuth Provider
# Social Auth (LinkedIn, optional)
LINKEDIN_CLIENT_ID=""
LINKEDIN_CLIENT_SECRET=""
# Custom OAuth Provider (optional)
OAUTH_PROVIDER_NAME=""
OAUTH_CLIENT_ID=""
OAUTH_CLIENT_SECRET=""
@@ -68,10 +68,21 @@ S3_FORCE_PATH_STYLE="true"
FLAG_DEBUG_PRINTER="false"
# This flag disables new signups, both on the web app and the server.
FLAG_DISABLE_SIGNUP="false"
FLAG_DISABLE_SIGNUPS="false"
# This flag disables email/password login. Disables email verification, forgot password, and reset password flows. Users can still sign up via social auth (Google/GitHub/Custom OAuth), unless FLAG_DISABLE_SIGNUPS is also set to true.
FLAG_DISABLE_EMAIL_AUTH="false"
# This flag disables the image processing.
# This is useful if you are using a machine with limited resources, like a Raspberry Pi.
FLAG_DISABLE_IMAGE_PROCESSING="false"
# --- Others ---
# Google Cloud API Key (optional)
# This is not used within Reactive Resume, but in src/scripts/fonts/generate.ts to generate a list of fonts served by Google Fonts.
# Note: Make sure "Google Fonts Developer API" is unrestricted.
GOOGLE_CLOUD_API_KEY=""
# --- Crowdin ---
CROWDIN_PROJECT_ID=""
CROWDIN_API_TOKEN=""
+1
View File
@@ -0,0 +1 @@
locales/*.po linguist-generated=true
+66 -66
View File
@@ -1,68 +1,68 @@
{
"$schema": "https://fundingjson.org/schema/v1.1.0.json",
"version": "v1.1.0",
"entity": {
"type": "individual",
"role": "maintainer",
"name": "Amruth Pillai",
"email": "im.amruth@gmail.com",
"description": "Software Engineer",
"webpageUrl": {
"url": "https://rxresu.me/funding.json"
}
},
"projects": [
{
"guid": "reactive-resume",
"name": "Reactive Resume",
"description": "A free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.",
"webpageUrl": {
"url": "https://rxresu.me"
},
"repositoryUrl": {
"url": "https://github.com/AmruthPillai/Reactive-Resume",
"wellKnown": "https://github.com/AmruthPillai/Reactive-Resume/blob/main/.github/.well-known/funding-manifest-urls"
},
"licenses": ["spdx:MIT"],
"tags": ["data", "design", "productivity", "resume-builder"]
}
],
"funding": {
"plans": [
{
"guid": "sponsor",
"status": "active",
"name": "Sponsor",
"description": "Support the project on a recurring basis by becoming a sponsor.",
"amount": 10,
"currency": "EUR",
"frequency": "monthly",
"channels": ["github", "open-collective"]
},
{
"guid": "donation",
"status": "active",
"name": "Donation",
"description": "Show your support for the project by making a one-time donation.",
"amount": 0,
"currency": "EUR",
"frequency": "one-time",
"channels": ["github", "open-collective"]
}
],
"channels": [
{
"guid": "github",
"type": "payment-provider",
"description": "GitHub Sponsors",
"address": "https://github.com/sponsors/AmruthPillai"
},
{
"guid": "open-collective",
"type": "payment-provider",
"description": "Open Collective",
"address": "https://opencollective.com/reactive-resume"
}
]
}
"$schema": "https://fundingjson.org/schema/v1.1.0.json",
"version": "v1.1.0",
"entity": {
"type": "individual",
"role": "maintainer",
"name": "Amruth Pillai",
"email": "im.amruth@gmail.com",
"description": "Software Engineer",
"webpageUrl": {
"url": "https://rxresu.me/funding.json"
}
},
"projects": [
{
"guid": "reactive-resume",
"name": "Reactive Resume",
"description": "A free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.",
"webpageUrl": {
"url": "https://rxresu.me"
},
"repositoryUrl": {
"url": "https://github.com/amruthpillai/reactive-resume",
"wellKnown": "https://github.com/amruthpillai/reactive-resume/blob/main/.github/.well-known/funding-manifest-urls"
},
"licenses": ["spdx:MIT"],
"tags": ["data", "design", "productivity", "resume-builder"]
}
],
"funding": {
"plans": [
{
"guid": "sponsor",
"status": "active",
"name": "Sponsor",
"description": "Support the project on a recurring basis by becoming a sponsor.",
"amount": 10,
"currency": "EUR",
"frequency": "monthly",
"channels": ["github", "open-collective"]
},
{
"guid": "donation",
"status": "active",
"name": "Donation",
"description": "Show your support for the project by making a one-time donation.",
"amount": 0,
"currency": "EUR",
"frequency": "one-time",
"channels": ["github", "open-collective"]
}
],
"channels": [
{
"guid": "github",
"type": "payment-provider",
"description": "GitHub Sponsors",
"address": "https://github.com/sponsors/AmruthPillai"
},
{
"guid": "open-collective",
"type": "payment-provider",
"description": "Open Collective",
"address": "https://opencollective.com/reactive-resume"
}
]
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
github: AmruthPillai
open_collective: reactive-resume
open_collective: reactive-resume
+2 -2
View File
@@ -3,7 +3,7 @@ name: ✨ Feature Request
description: Suggest an feature or idea that you would like to see in Reactive Resume
title: "[Feature] <title>"
labels: [feature, v5, needs triage]
labels: [enhancement, v5, needs triage]
assignees: "AmruthPillai"
body:
@@ -20,4 +20,4 @@ body:
label: Feature Description
description: A detailed description of the feature you would like to see in Reactive Resume. Please provide as much detail as possible as it will help me implement the feature faster.
validations:
required: true
required: true
+1 -1
View File
@@ -1 +1 @@
blank_issues_enabled: false
blank_issues_enabled: false
+31
View File
@@ -0,0 +1,31 @@
name: autofix.ci
on:
pull_request:
push:
branches: ["main"]
permissions:
contents: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
autofix:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: voidzero-dev/setup-vp@v1
with:
node-version: "24"
cache: true
- run: vp install
- run: vp test
- run: vp check --fix
- uses: autofix-ci/action@7a166d7532b277f34e16238930461bf77f9d7ed8
+58 -22
View File
@@ -2,9 +2,6 @@ name: Build Docker Image
on:
workflow_dispatch:
push:
branches: ["main"]
tags: ["v*.*.*"]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -12,6 +9,7 @@ concurrency:
env:
IMAGE: ${{ github.repository }}
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
build:
@@ -44,16 +42,16 @@ jobs:
run: echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -61,18 +59,17 @@ jobs:
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: |
ghcr.io/${{ env.IMAGE }}
docker.io/${{ env.IMAGE }}
tags: |
type=sha,format=short,suffix=-${{ matrix.arch }}
type=raw,value=v${{ steps.version.outputs.version }}-${{ matrix.arch }}
type=sha,prefix=sha-,suffix=-${{ matrix.arch }}
- name: Build and Push by Digest
id: build
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .
sbom: true
@@ -81,6 +78,7 @@ jobs:
platforms: ${{ matrix.platform }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
cache-from: type=gha,scope=${{ env.IMAGE }}-${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=${{ env.IMAGE }}-${{ matrix.arch }}
@@ -91,7 +89,7 @@ jobs:
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v6
uses: actions/upload-artifact@v7
with:
name: digests-${{ matrix.arch }}
path: /tmp/digests/*
@@ -111,7 +109,7 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
sparse-checkout: package.json
sparse-checkout-cone-mode: false
@@ -121,55 +119,93 @@ jobs:
run: echo "version=$(jq -r .version package.json)" >> "$GITHUB_OUTPUT"
- name: Download digests
uses: actions/download-artifact@v7
uses: actions/download-artifact@v8
with:
path: /tmp/digests
pattern: digests-*
merge-multiple: true
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Parse version components
id: semver
run: |
VERSION="${{ steps.version.outputs.version }}"
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
echo "major=$MAJOR" >> "$GITHUB_OUTPUT"
echo "minor=$MINOR" >> "$GITHUB_OUTPUT"
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: |
ghcr.io/${{ env.IMAGE }}
docker.io/${{ env.IMAGE }}
tags: |
type=sha,format=short
type=sha,prefix=sha-
type=raw,value=latest
type=raw,value=v${{ steps.version.outputs.version }}
type=raw,value=v${{ steps.semver.outputs.major }}.${{ steps.semver.outputs.minor }}
type=raw,value=v${{ steps.semver.outputs.major }}
- name: Create manifest list and push
id: manifest
working-directory: /tmp/digests
run: |
set -euo pipefail
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
--annotation "index:org.opencontainers.image.licenses=MIT" \
--annotation "index:org.opencontainers.image.title=Reactive Resume" \
--annotation "index:org.opencontainers.image.description=A free and open-source resume builder." \
--annotation "index:org.opencontainers.image.vendor=Amruth Pillai" \
--annotation "index:org.opencontainers.image.url=https://rxresu.me" \
--annotation "index:org.opencontainers.image.documentation=https://docs.rxresu.me" \
--annotation "index:org.opencontainers.image.source=https://github.com/amruthpillai/reactive-resume" \
--annotation "index:org.opencontainers.image.version=${{ steps.version.outputs.version }}" \
$(printf 'ghcr.io/${{ env.IMAGE }}@sha256:%s ' *) \
$(printf 'docker.io/${{ env.IMAGE }}@sha256:%s ' *)
# Get the digest of the multi-arch manifest
GHCR_DIGEST=$(docker buildx imagetools inspect ghcr.io/${{ env.IMAGE }}:v${{ steps.version.outputs.version }} --format '{{json .Manifest.Digest}}' | tr -d '"')
DOCKER_DIGEST=$(docker buildx imagetools inspect docker.io/${{ env.IMAGE }}:v${{ steps.version.outputs.version }} --format '{{json .Manifest.Digest}}' | tr -d '"')
echo "ghcr_digest=$GHCR_DIGEST" >> "$GITHUB_OUTPUT"
echo "docker_digest=$DOCKER_DIGEST" >> "$GITHUB_OUTPUT"
- name: Install Cosign
uses: sigstore/cosign-installer@v3
- name: Sign images with Cosign
run: |
# Sign GHCR image
cosign sign --yes ghcr.io/${{ env.IMAGE }}@${{ steps.manifest.outputs.ghcr_digest }}
# Sign Docker Hub image
cosign sign --yes docker.io/${{ env.IMAGE }}@${{ steps.manifest.outputs.docker_digest }}
- name: Inspect image
run: |
docker buildx imagetools inspect ghcr.io/${{ env.IMAGE }}:latest
docker buildx imagetools inspect ghcr.io/${{ env.IMAGE }}:v${{ steps.version.outputs.version }}
docker buildx imagetools inspect docker.io/${{ env.IMAGE }}:v${{ steps.version.outputs.version }}
- name: Redeploy Service
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
- name: Redeploy Stack
uses: appleboy/ssh-action@v1
with:
key: ${{ secrets.SSH_KEY }}
@@ -177,4 +213,4 @@ jobs:
username: ${{ secrets.SSH_USER }}
script: |
cd docker
./manage_stack.sh up reactive_resume
./manage_stack.sh up reactive_resume
+7 -1
View File
@@ -2,9 +2,12 @@ dist
.env*
/data
.nitro
.agents
.output
.vercel
.cursor
.claude
TODO.md
coverage
.netlify
.DS_Store
@@ -12,4 +15,7 @@ coverage
node_modules
!.env.example
public/sw.js
public/workbox-*.js
public/sw.js.map
scripts/**/*.json
public/workbox-*.js
public/workbox-*.js.map
-48
View File
@@ -1,48 +0,0 @@
stages:
- build
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
build-and-push:
stage: build
image: docker:24
services:
- docker:24-dind
rules:
- if: $CI_COMMIT_BRANCH == "main"
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_PIPELINE_SOURCE == "web"
before_script:
- apk add --no-cache jq
- echo "$CI_REGISTRY_PASSWORD" | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
- |
export VERSION=$(jq -r .version package.json)
echo "VERSION=$VERSION" >> build.env
script:
- source build.env
- |
SHORT_SHA=$CI_COMMIT_SHORT_SHA
PRIMARY_TAG="$CI_REGISTRY_IMAGE:$SHORT_SHA"
# Build the image
docker build -f ./Dockerfile -t $PRIMARY_TAG .
# Tag with additional tags
docker tag $PRIMARY_TAG $CI_REGISTRY_IMAGE:latest
if [ -n "$VERSION" ] && [ "$VERSION" != "null" ]; then
docker tag $PRIMARY_TAG $CI_REGISTRY_IMAGE:v$VERSION
fi
# Push all tags (only if not a merge request)
if [ "$CI_PIPELINE_SOURCE" != "merge_request_event" ]; then
docker push $PRIMARY_TAG
docker push $CI_REGISTRY_IMAGE:latest
if [ -n "$VERSION" ] && [ "$VERSION" != "null" ]; then
docker push $CI_REGISTRY_IMAGE:v$VERSION
fi
fi
after_script:
- docker logout $CI_REGISTRY || true
+9 -9
View File
@@ -2,16 +2,16 @@
const nextPackages = ["@monaco-editor/react"];
const betaPackages = ["drizzle-orm", "drizzle-kit", "@better-auth/core", "@better-auth/passkey", "better-auth"];
const betaPackages = ["drizzle-orm", "drizzle-kit", "drizzle-zod"];
/** @type {import('npm-check-updates').RunOptions} */
module.exports = {
upgrade: true,
install: "always",
packageManager: "pnpm",
target: (packageName) => {
if (nextPackages.includes(packageName)) return "@next";
if (betaPackages.includes(packageName)) return "@beta";
return "latest";
},
upgrade: true,
install: "always",
packageManager: "pnpm",
target: (packageName) => {
if (nextPackages.includes(packageName)) return "@next";
if (betaPackages.includes(packageName)) return "@beta";
return "latest";
},
};
+1
View File
@@ -0,0 +1 @@
vp staged
+7 -1
View File
@@ -1,3 +1,9 @@
{
"recommendations": ["biomejs.biome", "bradlc.vscode-tailwindcss", "lokalise.i18n-ally"]
"recommendations": [
"oxc.oxc-vscode",
"bradlc.vscode-tailwindcss",
"lokalise.i18n-ally",
"typescriptteam.native-preview",
"VoidZero.vite-plus-extension-pack"
]
}
+42 -41
View File
@@ -1,43 +1,44 @@
{
"[mdx]": {
"editor.defaultFormatter": "unifiedjs.vscode-mdx"
},
"biome.enabled": true,
"editor.codeActionsOnSave": {
"source.biome": "explicit",
"source.fixAll.biome": "explicit",
"source.organizeImports.biome": "explicit"
},
"editor.defaultFormatter": "biomejs.biome",
"eslint.enable": false,
"files.associations": {
"*.css": "tailwindcss"
},
"files.readonlyInclude": {
"locales/*.po": true,
"pnpm-lock.yaml": true,
"**/routeTree.gen.ts": true
},
"files.watcherExclude": {
"locales/*.po": true,
"pnpm-lock.yaml": true,
"**/routeTree.gen.ts": true
},
"i18n-ally.enabledParsers": ["po"],
"i18n-ally.localesPaths": ["locales"],
"i18n-ally.sourceLanguage": "en-US",
"prettier.enable": false,
"search.exclude": {
"locales/*.po": true,
"pnpm-lock.yaml": true,
"**/routeTree.gen.ts": true
},
"tailwindCSS.classFunctions": ["cn", "cva"],
"tailwindCSS.experimental.classRegex": [
["class:\\s*?[\"'`]([^\"'`]*).*?,"],
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
],
"tailwindCSS.experimental.configFile": "src/styles/globals.css",
"typescript.tsdk": "node_modules/typescript/lib"
"[typescript]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll.oxc": "explicit"
},
"editor.defaultFormatter": "oxc.oxc-vscode",
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file",
"files.associations": {
"*.css": "tailwindcss"
},
"files.readonlyInclude": {
"**/routeTree.gen.ts": true,
"pnpm-lock.yaml": true
},
"files.watcherExclude": {
"**/routeTree.gen.ts": true,
"locales/**.po": true,
"pnpm-lock.yaml": true
},
"i18n-ally.enabledParsers": ["po"],
"i18n-ally.localesPaths": ["locales"],
"i18n-ally.sourceLanguage": "en-US",
"oxc.enable.oxfmt": true,
"oxc.enable.oxlint": true,
"oxc.configPath": "./vite.config.ts",
"oxc.fmt.configPath": "./vite.config.ts",
"search.exclude": {
"**/routeTree.gen.ts": true,
"locales/**.po": true,
"pnpm-lock.yaml": true
},
"tailwindCSS.classFunctions": ["cn", "cva"],
"tailwindCSS.experimental.classRegex": [
["class:\\s*?[\"'`]([^\"'`]*).*?,"],
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
],
"tailwindCSS.experimental.configFile": "src/styles/globals.css",
"typescript.experimental.useTsgo": true
}
+131
View File
@@ -0,0 +1,131 @@
## Overview
Reactive Resume is a single-package full-stack TypeScript app (not a monorepo) built with [TanStack Start](https://tanstack.com/start/latest/docs/framework/react/overview) (React, Vite, Nitro). It serves both frontend and API on port 3000.
This project uses [Vite+](https://vite.dev/blog/announcing-viteplus), a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called `vp`. All modules should be imported from the `vite-plus` dependency (e.g., `import { defineConfig } from 'vite-plus'` or `import { expect, test, vi } from 'vite-plus/test'`).
## Key Libraries
| Area | Library | Docs |
| -------------------- | ------------------------------------------------------------------------ | ---------------------------------- |
| Frontend framework | React | https://react.dev |
| Full-stack framework | TanStack Start | https://tanstack.com/start/latest |
| Router | TanStack React Router | https://tanstack.com/router/latest |
| Server state | TanStack React Query | https://tanstack.com/query/latest |
| Client state | Zustand (+ Zundo for undo/redo, Immer for immutable updates) | https://zustand.docs.pmnd.rs |
| Type-safe API | oRPC | https://orpc.unnoq.com |
| Database ORM | Drizzle ORM (PostgreSQL) | https://orm.drizzle.team |
| Authentication | Better Auth (+ Drizzle adapter, OAuth provider, API keys, 2FA, Passkeys) | https://www.better-auth.com |
| Styling | Tailwind CSS | https://tailwindcss.com |
| UI Components | shadcn/ui (built on Base UI) | https://ui.shadcn.com |
| Icons | Phosphor Icons | https://phosphoricons.com |
| Forms | React Hook Form (+ Zod resolvers) | https://react-hook-form.com |
| Rich text editor | Tiptap | https://tiptap.dev |
| Validation | Zod | https://zod.dev |
| AI | Vercel AI SDK (OpenAI, Anthropic, Google, Ollama providers) | https://ai-sdk.dev |
| MCP | Model Context Protocol SDK | https://modelcontextprotocol.io |
| i18n | Lingui | https://lingui.dev |
| Animations | Motion (Framer Motion) | https://motion.dev |
| PDF export | Puppeteer Core (via Browserless) | https://pptr.dev |
| Drag and drop | dnd-kit | https://dndkit.com |
| Server engine | Nitro | https://nitro.build |
| PWA | Vite PWA Plugin | https://vite-pwa-org.netlify.app |
| Unused deps | Knip | https://knip.dev |
## Project Structure
```
src/
components/ UI, resume, layout, animation, theme, locale components
routes/ File-based routing (TanStack React Router)
integrations/ Feature modules (auth, drizzle, orpc, ai, email, jobs, mcp, storage)
schema/ Zod schemas for resume data validation
utils/ Utility functions (locale, theme, env, resume processing)
dialogs/ Modal/dialog components
hooks/ Custom React hooks
styles/ CSS and Tailwind configuration
stores/ Zustand stores (resume, AI, dialog, command palette)
migrations/ Drizzle database migrations
locales/ Lingui i18n message catalogs (47+ locales)
```
### Key Config Files
- `vite.config.ts` — Vite + Nitro + TanStack Start + PWA + Tailwind + Lingui
- `drizzle.config.ts` — PostgreSQL dialect, schema at `./src/integrations/drizzle/schema.ts`
- `tsconfig.json` — ES2022, strict mode, path alias `@/*` → `./src/*`
- `lingui.config.ts` — i18n extraction and locale configuration
- `components.json` — shadcn CLI configuration
### API Architecture
- **oRPC API** (`/api/rpc/*`) — Type-safe RPC with routers for: `ai`, `auth`, `resume`, `storage`, `printer`, `jobs`, `statistics`, `flags`. Three procedure types: `publicProcedure`, `protectedProcedure`, `serverOnlyProcedure`.
- **Better Auth API** (`/api/auth/*`) — OAuth, session management, social provider callbacks.
- **MCP Server** (`/mcp/`) — Model Context Protocol with OAuth Bearer tokens and API key auth. Exposes resumes as resources and tools for resume CRUD.
## Infrastructure Services
Before running the dev server, Docker must be running with at least PostgreSQL. Start services via `compose.dev.yml`:
```bash
sudo dockerd &>/var/log/dockerd.log &
sudo docker compose -f compose.dev.yml up -d postgres browserless
```
- **PostgreSQL** (port 5432) — required. The app auto-runs Drizzle migrations on startup via a Nitro plugin.
- **Browserless** (port 4000) — required for PDF export. Maps container port 3000 to host port 4000.
## Environment Variables
Copy `.env.example` to `.env` if not present. Key notes for local dev:
- `APP_URL` — local dev server origin on port 3000.
- `PRINTER_APP_URL` — must use the Docker bridge gateway IP (not localhost) so the Browserless container can reach the app on the host. Get the IP with: `sudo docker network inspect reactive_resume_default --format '{{range .IPAM.Config}}{{.Gateway}}{{end}}'`
- `PRINTER_ENDPOINT` — websocket URL to Browserless on host port 4000 with token `1234567890`.
- `DATABASE_URL` — PostgreSQL connection using `postgres:postgres` credentials on localhost:5432.
- S3/Storage and SMTP vars can be left empty — the app falls back to local filesystem and console-logged emails.
## Common Commands
`vp` is the global CLI for Vite+. Do not use pnpm/npm/yarn directly — Vite+ wraps the underlying package manager.
| Task | Command |
| -------------------------- | --------------------------------------------------------------- |
| Install dependencies | `vp install` |
| Dev server (port 3000) | `vp dev` |
| Lint (Oxlint, type-aware) | `vp lint --type-aware` |
| Format (Oxfmt) | `vp fmt` |
| Check (lint + fmt + types) | `vp check` |
| Typecheck | `pnpm typecheck` (uses tsgo) |
| Run tests | `vp test` |
| DB migrations | `pnpm db:generate` / `pnpm db:migrate` (auto-runs on dev start) |
| DB studio | `pnpm db:studio` |
| i18n extraction | `pnpm lingui:extract` |
| Add a dependency | `vp add <package>` |
| Remove a dependency | `vp remove <package>` |
| One-off binary | `vp dlx <package>` |
| Build for production | `vp build` |
| Preview production build | `vp preview` |
| Start production server | `pnpm start` |
## Vite+ Pitfalls
- **Do not use pnpm/npm/yarn directly** for package operations — use `vp add`, `vp remove`, `vp install`, etc.
- **Do not run `vp vitest` or `vp oxlint`** — they don't exist. Use `vp test` and `vp lint`.
- **Do not install Vitest, Oxlint, Oxfmt, or tsdown directly** — Vite+ bundles them.
- **Import from `vite-plus`**, not from `vite` or `vitest` directly (e.g., `import { defineConfig } from 'vite-plus'`).
- **Vite+ commands take precedence** over `package.json` scripts. If there's a naming conflict, use `vp run <script>`.
- **Use `vp dlx`** instead of `npx` or `pnpm dlx`.
- **Type-aware linting** works out of the box with `vp lint --type-aware` — no need to install `oxlint-tsgolint`.
## Gotchas
- The Docker daemon needs `fuse-overlayfs` storage driver and `iptables-legacy` in the cloud VM (nested container environment).
- `pnpm.onlyBuiltDependencies` in `package.json` controls which packages are allowed to run install scripts — no interactive `pnpm approve-builds` needed.
- Email verification is optional in dev — after signup, click "Continue" to skip.
- Vite and Nitro use beta/nightly builds. Occasional upstream issues may occur.
## Review Checklist for Agents
- [ ] Run `vp install` after pulling remote changes and before getting started.
- [ ] Run `pnpm lint:fix`, `pnpm fmt:fix`, `pnpm typecheck` and `vp test` to validate changes.
Symlink
+1
View File
@@ -0,0 +1 @@
AGENTS.md
+16 -1
View File
@@ -35,6 +35,18 @@ RUN pnpm run build
# ---------- Runtime Layer ----------
FROM node:24-slim AS runtime
LABEL maintainer="amruthpillai"
LABEL org.opencontainers.image.licenses="MIT"
LABEL org.opencontainers.image.title="Reactive Resume"
LABEL org.opencontainers.image.description="A free and open-source resume builder."
LABEL org.opencontainers.image.vendor="Amruth Pillai"
LABEL org.opencontainers.image.url="https://rxresu.me"
LABEL org.opencontainers.image.documentation="https://docs.rxresu.me"
LABEL org.opencontainers.image.source="https://github.com/amruthpillai/reactive-resume"
RUN apt-get update && apt-get install -y --no-install-recommends curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
ENV NODE_ENV=production
@@ -45,4 +57,7 @@ COPY --from=dependencies /tmp/prod/node_modules ./node_modules
EXPOSE 3000/tcp
ENTRYPOINT ["node", "-r", "reflect-metadata", ".output/server/index.mjs"]
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
ENTRYPOINT ["node", ".output/server/index.mjs"]
-194
View File
@@ -1,194 +0,0 @@
# Feature Request: AI Chat Builder for Resume Editing
I don't know much about this, so I'm looking for volunteers to help with the implementation of this feature I'd like to see on Reactive Resume, and I hope the community finds interest in this feature too.
## Prerequisites
For this feature to work, the following conditions must be met:
- User is logged into Reactive Resume
- User has set up AI integration on their account
- This means that an AI provider, model and API key should be available for usage on the browser through `useAIStore`
## User Story
1. I have just created a new resume, or I am currently editing a resume I made earlier and I'm on the builder screen.
2. I know what I want, I need to make a few edits here and there, rewrite my summary so it reads better, but I'm lazy.
3. I see a button (outline) on the header, right next to the name on the resume and the menu icon that reads **"Build with AI"** and has a sparkles ✨ icon on its left.
- This button is only enabled if I have AI integration enabled. If I don't, this button shouldn't be visible at all so as to not hinder the user experience for non-AI enabled users.
4. Clicking on the button displays a chat overlay that can be toggled open/close which covers the right portion of the screen (about 380px width).
5. The chat window should animate open, sliding from the bottom. Below the window, there should be a floating action button which controls the visibility of this window. If the button hasn't been interacted with in the last 1 minute, hide the button until the user clicks on the "Build with AI" button again.
6. The AI chat should display an initial greeting message. Users can type in what they want to change specifically in the resume, some examples include:
- "Rewrite the professional summary"
- "Translate all of the section headings to German"
- "Make my work experience descriptions more impactful"
- "Add keywords related to software engineering"
7. The request should be sent using `await client.ai.chat({ input: { aiStoreData, resumeId } })`. Ideally, the oRPC chat route should explicitly accept the `resumeId` in its input and have it available in the context, ensuring that any AI-driven changes or updates are accurately mapped to the correct resume.
8. This should display the changes to be made to the resume and apply them. Maybe using tools? I'm not too sure if that's what tools are used for.
## What Already Exists
The codebase already has the foundational pieces in place:
### AI Store (`src/integrations/ai/store.ts`)
Manages the AI configuration stored in localStorage:
```typescript
type AIStoreState = {
enabled: boolean;
provider: AIProvider; // "openai" | "gemini" | "anthropic" | "ollama" | ...;
model: string;
apiKey: string;
baseURL: string;
testStatus: TestStatus;
};
```
You can check if AI is enabled via:
```typescript
const enabled = useAIStore((state) => state.enabled);
```
### oRPC AI Router (`src/integrations/orpc/router/ai.ts`)
Existing AI endpoints that demonstrate streaming patterns:
```typescript
// Example: testConnection streams a response
testConnection: protectedProcedure
.input(z.object({ provider, model, apiKey, baseURL }))
.handler(async function* ({ input }) {
const stream = streamText({
model: getModel(input),
messages: [{ role: "user", content: 'Respond with "1"' }],
});
yield* stream.textStream;
}),
```
The router also uses `generateText` with structured output for parsing documents - this pattern could be useful for applying changes to resume data.
### Resume Store (`src/components/resume/store/resume.ts`)
Provides `updateResumeData()` for modifying the resume:
```typescript
updateResumeData: (fn) => {
set((state) => {
if (!state.resume) return state;
if (state.resume.isLocked) {
// show error toast
return state;
}
fn(state.resume.data as WritableDraft<ResumeData>);
syncResume(current(state.resume));
});
},
```
### Builder Header (`src/routes/builder/$resumeId/-components/header.tsx`)
This is where the "Build with AI" button should be placed, next to the resume name and dropdown menu.
## Technical Considerations
Here are some implementation hints for anyone interested in picking this up:
### 1. Button Placement
Add the button in the `BuilderHeader` component, conditionally rendered based on `useAIStore().enabled`:
```typescript
const enabled = useAIStore((state) => state.enabled);
// In the JSX, only show if enabled
{enabled && (
<Button variant="outline" onClick={openChatPanel}>
<SparkleIcon />
Build with AI
</Button>
)}
```
### 2. Chat Panel Component
- Create a new component (e.g., `AIChatPanel`) that renders as an overlay
- Width: ~380px, positioned on the right side of the screen
- Animate in from the bottom using Framer Motion (already in the project as `motion/react`)
- Include a floating action button (FAB) below the panel for quick toggle
- Auto-hide the FAB after 1 minute of inactivity
### 3. Chat State Management
Consider creating a new Zustand store for chat state:
```typescript
type AIChatStore = {
isOpen: boolean;
messages: ChatMessage[];
lastInteraction: number;
// actions...
};
```
### 4. oRPC Route for Chat
Create a new route in `src/integrations/orpc/router/ai.ts`:
```typescript
chat: protectedProcedure
.input(z.object({
...aiCredentialsSchema.shape,
resumeId: z.string(),
message: z.string(),
}))
.handler(async function* ({ input, context }) {
// Get resume data for context
// Stream AI response
// Optionally use tools for structured changes
}),
```
### 5. Applying Changes
The tricky part is how to apply AI-suggested changes to the resume. Some options:
- **AI SDK Tools**: Use the Vercel AI SDK's tool calling feature to let the AI invoke specific functions like `updateSummary`, `translateHeadings`, etc.
- **Structured Output**: Have the AI return a JSON patch or specific update instructions that can be applied via `updateResumeData()`
- **Diff Display**: Show proposed changes before applying them, letting users accept/reject
### 6. Resume Data Schema
The resume data schema is defined in `src/schema/resume/data.ts` and includes sections like:
- `basics` (name, headline, summary, contact info)
- `experience`, `education`, `skills`, `projects`, etc.
- `metadata` (template, typography, colors)
- `customSections`
## Design Principles
The premise is simple and nothing that hasn't been done before, but I'd like to see it done **subtly** as this is not an AI-first app, it should just be AI-enabled.
- The feature should feel like an optional enhancement, not a core requirement
- Non-AI users should not feel like they're missing out or see disabled features
- The UI should be clean and non-intrusive
- Performance should not be impacted when AI features are not in use
## Getting Started
If you're interested in contributing:
1. Fork the repository
2. Set up the development environment (see README)
3. Configure AI settings in Dashboard > Settings > AI
4. Start exploring the code references mentioned above
## Questions?
Feel free to ask questions in the comments below. I'm happy to provide more context or clarify any requirements.
---
**Labels**: `enhancement`, `help wanted`, `good first issue`, `ai`
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 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.
+40 -42
View File
@@ -1,17 +1,3 @@
<!--
<div align="center" markdown="1">
<a href="https://go.warp.dev/Reactive-Resume">
<img alt="Warp Sponsorship" width="400" src="https://github.com/warpdotdev/brand-assets/blob/main/Github/Sponsor/Warp-Github-LG-03.png?raw=true" />
</a>
### [Warp, built for coding with multiple AI agents.](https://go.warp.dev/Reactive-Resume)
[Available for MacOS, Linux, & Windows](https://go.warp.dev/Reactive-Resume)
</div>
---
-->
<div align="center">
<a href="https://rxresu.me">
<img src="public/opengraph/banner.jpg" alt="Reactive Resume" />
@@ -28,15 +14,15 @@
</p>
<p>
<img src="https://img.shields.io/github/stars/AmruthPillai/Reactive-Resume?style=flat-square" alt="Stars" />
<img src="https://img.shields.io/github/license/AmruthPillai/Reactive-Resume?style=flat-square" alt="License" />
<img src="https://img.shields.io/github/package-json/v/amruthpillai/reactive-resume?style=flat-square" alt="Reactive Resume version">
<img src="https://img.shields.io/github/stars/amruthpillai/Reactive-Resume?style=flat-square" alt="GitHub Stars">
<img src="https://img.shields.io/github/license/amruthpillai/Reactive-Resume?style=flat-square" alt="License" />
<img src="https://img.shields.io/docker/pulls/amruthpillai/reactive-resume?style=flat-square" alt="Docker Pulls" />
<a href="https://discord.gg/hzwkZbyvUW"><img src="https://img.shields.io/discord/1173518977851473940?label=Discord&style=flat-square&logo=discord" alt="Discord" /></a>
<a href="https://discord.gg/aSyA5ZSxpb"><img src="https://img.shields.io/discord/1173518977851473940?style=flat-square&label=discord" alt="Discord" /></a>
<a href="https://crowdin.com/project/reactive-resume"><img src="https://badges.crowdin.net/reactive-resume/localized.svg?style=flat-square" alt="Crowdin" /></a>
<a href="https://opencollective.com/reactive-resume"><img src="https://img.shields.io/opencollective/all/reactive-resume?style=flat-square" alt="Open Collective" /></a>
<a href="https://github.com/sponsors/AmruthPillai"><img src="https://img.shields.io/github/sponsors/AmruthPillai?style=flat-square&label=sponsors" alt="Sponsors" /></a>
<a href="https://opencollective.com/reactive-resume"><img src="https://img.shields.io/opencollective/backers/reactive-resume?style=flat-square&label=donations" alt="Donations" /></a>
</p>
<a href="https://www.producthunt.com/products/reactive-resume?embed=true&amp;utm_source=badge-featured&amp;utm_medium=badge&amp;utm_campaign=badge-reactive-resume-v5-2" target="_blank" rel="noopener noreferrer"><img alt="Reactive Resume v5 - A free and open-source resume builder. | Product Hunt" width="250" height="54" src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1065182&amp;theme=light&amp;t=1768850745585"></a>
</div>
---
@@ -149,8 +135,8 @@ The quickest way to run Reactive Resume locally:
```bash
# Clone the repository
git clone https://github.com/AmruthPillai/Reactive-Resume.git
cd Reactive-Resume
git clone https://github.com/amruthpillai/reactive-resume.git
cd reactive-resume
# Start all services
docker compose up -d
@@ -159,40 +145,42 @@ docker compose up -d
open http://localhost:3000
```
[![Build with Ona](https://ona.com/build-with-ona.svg)](https://app.ona.com/#https://github.com/amruthpillai/reactive-resume)
For detailed setup instructions, environment configuration, and self-hosting guides, see the [documentation](https://docs.rxresu.me).
## 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 | Radix UI |
| State Management | Zustand + TanStack Query |
| 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 | Radix UI |
| State Management | Zustand + TanStack Query |
## Documentation
Comprehensive guides are available at [docs.rxresu.me](https://docs.rxresu.me):
| Guide | Description |
| --------------------------------------------------------------------------- | --------------------------------- |
| [Getting Started](https://docs.rxresu.me/getting-started) | First-time setup and basic usage |
| [Self-Hosting](https://docs.rxresu.me/guides/self-hosting-with-docker) | Deploy on your own server |
| [Development Setup](https://docs.rxresu.me/contributing/development) | Local development environment |
| [Project Architecture](https://docs.rxresu.me/contributing/architecture) | Codebase structure and patterns |
| [Exporting Your Resume](https://docs.rxresu.me/guides/exporting-your-resume)| PDF and JSON export options |
| Guide | Description |
| ---------------------------------------------------------------------------- | -------------------------------- |
| [Getting Started](https://docs.rxresu.me/getting-started) | First-time setup and basic usage |
| [Self-Hosting](https://docs.rxresu.me/self-hosting/docker) | Deploy on your own server |
| [Development Setup](https://docs.rxresu.me/contributing/development) | Local development environment |
| [Project Architecture](https://docs.rxresu.me/contributing/architecture) | Codebase structure and patterns |
| [Exporting Your Resume](https://docs.rxresu.me/guides/exporting-your-resume) | PDF and JSON export options |
## Self-Hosting
Reactive Resume can be self-hosted using Docker. The stack includes:
- **PostgreSQL** — Database for storing user data and resumes
- **Gotenberg** — Headless Chrome service for PDF generation
- **Printer** — Headless Chromium service for PDF and screenshot generation
- **SeaweedFS** (optional) — S3-compatible storage for file uploads
Pull the latest image from Docker Hub or GitHub Container Registry:
@@ -205,7 +193,7 @@ docker pull amruthpillai/reactive-resume:latest
docker pull ghcr.io/amruthpillai/reactive-resume:latest
```
See the [self-hosting guide](https://docs.rxresu.me/guides/self-hosting-with-docker) for complete instructions.
See the [self-hosting guide](https://docs.rxresu.me/self-hosting/docker) for complete instructions.
## Support
@@ -227,6 +215,16 @@ Other ways to support:
- Improve documentation
- Help with translations
## Star History
<a href="https://www.star-history.com/#amruthpillai/reactive-resume&type=date&legend=top-left">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=amruthpillai/reactive-resume&type=date&theme=dark&legend=top-left" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=amruthpillai/reactive-resume&type=date&legend=top-left" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=amruthpillai/reactive-resume&type=date&legend=top-left" />
</picture>
</a>
## Contributing
Contributions make open-source thrive. Whether fixing a typo or adding a feature, all contributions are welcome.
-63
View File
@@ -1,63 +0,0 @@
{
"$schema": "node_modules/@biomejs/biome/configuration_schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true,
"defaultBranch": "main"
},
"files": {
"ignoreUnknown": true,
"includes": ["**", "!**/webfontlist.json", "!**/docs/spec.json", "!**/src/routeTree.gen.ts"]
},
"formatter": {
"lineWidth": 120,
"indentStyle": "tab"
},
"assist": {
"actions": {
"recommended": true,
"source": {
"organizeImports": "on",
"useSortedProperties": "on"
}
}
},
"linter": {
"rules": {
"a11y": "off",
"recommended": true,
"suspicious": {
"noArrayIndexKey": "off"
},
"correctness": {
"noUnknownTypeSelector": "off",
"noUnusedImports": {
"fix": "safe",
"level": "error",
"options": {}
}
},
"nursery": {
"useSortedClasses": {
"fix": "safe",
"level": "warn",
"options": {
"functions": ["cn", "cva"],
"attributes": ["class", "className"]
}
}
}
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
},
"css": {
"parser": {
"tailwindDirectives": true
}
}
}
-3280
View File
File diff suppressed because it is too large Load Diff
+21 -24
View File
@@ -1,26 +1,23 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "radix-vega",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/styles.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "phosphor",
"menuColor": "default",
"menuAccent": "subtle",
"aliases": {
"components": "@/components",
"utils": "@/utils",
"ui": "@/components/ui",
"lib": "@/utils",
"hooks": "@/hooks"
},
"registries": {
"@animate-ui": "https://animate-ui.com/r/{name}.json"
}
"$schema": "https://ui.shadcn.com/schema.json",
"style": "base-vega",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/styles.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"iconLibrary": "phosphor",
"menuColor": "default",
"menuAccent": "bold",
"aliases": {
"components": "@/components",
"utils": "@/utils/style",
"ui": "@/components/ui",
"lib": "@/utils",
"hooks": "@/hooks"
}
}
+40 -21
View File
@@ -1,13 +1,28 @@
name: reactive_resume
services:
adminer:
image: adminer:latest
restart: unless-stopped
ports:
- "8080:8080"
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080"]
start_period: 10s
interval: 30s
timeout: 10s
retries: 3
postgres:
image: postgres:18
image: postgres:latest
restart: unless-stopped
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- postgres_data:/var/lib/postgresql
ports:
@@ -19,25 +34,29 @@ services:
timeout: 10s
retries: 3
gotenberg:
image: gotenberg/gotenberg:8
browserless:
image: ghcr.io/browserless/chromium:latest
restart: unless-stopped
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- WEBHOOK_DISABLE=true
- CHROMIUM_AUTO_START=true
- LIBREOFFICE_DISABLE_ROUTES=true
- PROMETHEUS_DISABLE_COLLECT=true
- CHROMIUM_HOST_RESOLVER_RULES=MAP localhost host.docker.internal
ports:
- "4000:3000"
environment:
- QUEUED=10
- HEALTH=true
- CONCURRENT=5
- TOKEN=1234567890
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
start_period: 10s
interval: 30s
timeout: 10s
retries: 3
test: ["CMD", "curl", "-f", "http://localhost:3000/pressure?token=1234567890"]
interval: 10s
timeout: 5s
retries: 10
# As an alternative to browserless, you can also use a lightweight image like chromedp/headless-shell:latest
# See https://docs.rxresu.me/self-hosting/docker#alternative-printer-options for more information.
chrome:
image: chromedp/headless-shell:latest
restart: unless-stopped
ports:
- "9222:9222"
seaweedfs:
image: chrislusf/seaweedfs:latest
@@ -57,7 +76,7 @@ services:
timeout: 10s
retries: 3
seaweedfs-create-bucket:
seaweedfs_create_bucket:
image: quay.io/minio/mc:latest
restart: on-failure
entrypoint: >
@@ -88,6 +107,6 @@ services:
retries: 3
volumes:
mailpit_data:
postgres_data:
seaweedfs_data:
mailpit_data:
+30 -30
View File
@@ -2,12 +2,12 @@ name: reactive_resume
services:
postgres:
image: postgres:18
image: postgres:latest
restart: unless-stopped
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
- postgres_data:/var/lib/postgresql
healthcheck:
@@ -17,22 +17,27 @@ services:
timeout: 10s
retries: 3
gotenberg:
image: gotenberg/gotenberg:8
browserless:
image: ghcr.io/browserless/chromium:latest
restart: unless-stopped
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- WEBHOOK_DISABLE=true
- CHROMIUM_AUTO_START=true
- LIBREOFFICE_DISABLE_ROUTES=true
- PROMETHEUS_DISABLE_COLLECT=true
- QUEUED=10
- HEALTH=true
- CONCURRENT=5
- TOKEN=1234567890
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
start_period: 10s
interval: 30s
timeout: 10s
retries: 3
test: ["CMD", "curl", "-f", "http://localhost:3000/pressure?token=1234567890"]
interval: 10s
timeout: 5s
retries: 10
# As an alternative to browserless, you can also use a lightweight image like chromedp/headless-shell:latest
# See https://docs.rxresu.me/self-hosting/docker#alternative-printer-options for more information.
# chrome:
# image: chromedp/headless-shell:latest
# restart: unless-stopped
# ports:
# - "9222:9222"
seaweedfs:
image: chrislusf/seaweedfs:latest
@@ -50,7 +55,7 @@ services:
timeout: 10s
retries: 3
seaweedfs-create-bucket:
seaweedfs_create_bucket:
image: quay.io/minio/mc:latest
restart: on-failure
entrypoint: >
@@ -64,7 +69,7 @@ services:
seaweedfs:
condition: service_healthy
app:
reactive_resume:
image: amruthpillai/reactive-resume:latest
# image: ghcr.io/amruthpillai/reactive-resume:latest
environment:
@@ -72,9 +77,10 @@ services:
- TZ=Etc/UTC
- NODE_ENV=production
- APP_URL=http://localhost:3000
- PRINTER_APP_URL=http://app:3000
- PRINTER_APP_URL=http://reactive_resume:3000
# Printer
- GOTENBERG_ENDPOINT=http://gotenberg:3000
- PRINTER_ENDPOINT=ws://browserless:3000?token=1234567890
# - PRINTER_ENDPOINT=http://chrome:9222 # Or, if you're using chromedp/headless-shell
# Database
- DATABASE_URL=postgresql://postgres:postgres@postgres:5432/postgres
# Authentication
@@ -92,18 +98,12 @@ services:
depends_on:
postgres:
condition: service_healthy
gotenberg:
browserless:
condition: service_healthy
seaweedfs-create-bucket:
seaweedfs_create_bucket:
condition: service_completed_successfully
healthcheck:
test:
[
"CMD",
"node",
"-e",
"fetch('http://localhost:3000/api/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))",
]
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
start_period: 10s
interval: 30s
timeout: 10s
+7 -8
View File
@@ -1,13 +1,12 @@
project_id_env: CROWDIN_PROJECT_ID
api_token_env: CROWDIN_API_TOKEN
preserve_hierarchy: true
api_token_env: CROWDIN_API_TOKEN
project_id_env: CROWDIN_PROJECT_ID
commit_message: "[ci skip]"
pull_request_title: "Sync Translations from Crowdin"
pull_request_labels: ["l10n"]
pull_request_reviewers: ["amruthpillai"]
pull_request_title: Sync Translations from Crowdin
pull_request_labels:
- l10n
pull_request_reviewers:
- amruthpillai
files:
- source: /locales/en-US.po
translation: /locales/%locale%.%file_extension%
-12
View File
@@ -1,12 +0,0 @@
FROM postgres:latest
COPY ./postgresql.conf /etc/postgresql/postgresql.conf
COPY ./init.sql /docker-entrypoint-initdb.d/
RUN chown postgres:postgres /etc/postgresql/postgresql.conf && \
chmod 644 /etc/postgresql/postgresql.conf
EXPOSE 5432
CMD ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"]
-46
View File
@@ -1,46 +0,0 @@
-- Enable pg_stat_statements extension
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
-- Enable other useful extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- UUID generation
CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- Cryptographic functions
CREATE EXTENSION IF NOT EXISTS "btree_gin"; -- GIN indexes for btree types
CREATE EXTENSION IF NOT EXISTS "btree_gist"; -- GIST indexes for btree types
-- Create a function to reset pg_stat_statements (useful for debugging)
CREATE OR REPLACE FUNCTION reset_query_stats()
RETURNS void AS $$
BEGIN
PERFORM pg_stat_statements_reset();
END;
$$ LANGUAGE plpgsql;
-- Create a view for easier query analysis
CREATE OR REPLACE VIEW slow_queries AS
SELECT
query,
calls,
ROUND(total_exec_time::numeric, 2) AS total_time_ms,
ROUND(mean_exec_time::numeric, 2) AS mean_time_ms,
ROUND(max_exec_time::numeric, 2) AS max_time_ms,
ROUND((100 * total_exec_time / SUM(total_exec_time) OVER ())::numeric, 2) AS percentage,
rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC;
-- Create a view for most frequent queries
CREATE OR REPLACE VIEW frequent_queries AS
SELECT
query,
calls,
ROUND(mean_exec_time::numeric, 2) AS mean_time_ms,
ROUND(total_exec_time::numeric, 2) AS total_time_ms,
rows
FROM pg_stat_statements
ORDER BY calls DESC;
-- Notification for successful initialization
DO $$
BEGIN
RAISE NOTICE 'Database initialized with pg_stat_statements and helper views';
END $$;
-122
View File
@@ -1,122 +0,0 @@
# -----------------------------
# PostgreSQL 18 configuration file
# Optimized for: 8GB RAM, 6 vCPU, KVM Virtual Machine
# -----------------------------
# CONNECTIONS AND AUTHENTICATION
listen_addresses = '*'
max_connections = 100
superuser_reserved_connections = 3
# MEMORY SETTINGS
shared_buffers = 2GB
huge_pages = try
effective_cache_size = 6GB
maintenance_work_mem = 512MB
work_mem = 20MB
# QUERY TUNING
random_page_cost = 1.1
effective_io_concurrency = 200
default_statistics_target = 100
# WRITE AHEAD LOG (WAL)
wal_level = replica
wal_buffers = 16MB
min_wal_size = 1GB
max_wal_size = 4GB
wal_compression = on
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min
# BACKGROUND WRITER
bgwriter_delay = 200ms
bgwriter_lru_maxpages = 100
bgwriter_lru_multiplier = 2.0
# AUTOVACUUM
autovacuum = on
autovacuum_max_workers = 3
autovacuum_naptime = 1min
autovacuum_vacuum_threshold = 50
autovacuum_vacuum_scale_factor = 0.1
autovacuum_analyze_threshold = 50
autovacuum_analyze_scale_factor = 0.05
autovacuum_vacuum_cost_delay = 2ms
autovacuum_vacuum_cost_limit = 200
# MONITORING AND STATISTICS
track_activities = on
track_counts = on
track_io_timing = on
track_functions = all
track_wal_io_timing = on
compute_query_id = on
# pg_stat_statements configuration
pg_stat_statements.track = all
pg_stat_statements.max = 10000
pg_stat_statements.track_utility = on
pg_stat_statements.save = on
# LOGGING
log_destination = 'stderr'
logging_collector = on
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_file_mode = 0600
log_rotation_age = 1d
log_rotation_size = 100MB
log_truncate_on_rotation = on
# What to log
log_min_duration_statement = 1000
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_checkpoints = on
log_connections = on
log_disconnections = on
log_duration = off
log_lock_waits = on
log_statement = 'none'
log_temp_files = 0
log_timezone = 'UTC'
# LOCALE AND FORMATTING
datestyle = 'iso, mdy'
timezone = 'UTC'
lc_messages = 'en_US.utf8'
lc_monetary = 'en_US.utf8'
lc_numeric = 'en_US.utf8'
lc_time = 'en_US.utf8'
default_text_search_config = 'pg_catalog.english'
# LOCK MANAGEMENT
deadlock_timeout = 1s
max_locks_per_transaction = 64
max_pred_locks_per_transaction = 64
# CLIENT CONNECTION DEFAULTS
search_path = '"$user", public'
idle_in_transaction_session_timeout = 600000
statement_timeout = 0
# PARALLEL QUERY EXECUTION
max_worker_processes = 6
max_parallel_workers_per_gather = 3
max_parallel_workers = 6
max_parallel_maintenance_workers = 3
parallel_leader_participation = on
# INCREMENTAL BACKUP
summarize_wal = on
# VACUUM OPTIMIZATION
vacuum_buffer_usage_limit = 256kB
# VECTOR EXTENSION SETTINGS
maintenance_work_mem = 512MB
max_parallel_maintenance_workers = 3
work_mem = 32MB
# EXTENSIONS
shared_preload_libraries = 'pg_stat_statements'
-206
View File
@@ -1,206 +0,0 @@
services:
postgres:
image: postgres:18
command: postgres -c config_file=/etc/postgresql.conf
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
configs:
- source: reactive_resume_postgres_config
target: /etc/postgresql.conf
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER -d $POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
gotenberg:
image: gotenberg/gotenberg:8
networks:
- reactive_resume_network
environment:
- WEBHOOK_DISABLE=true
- CHROMIUM_AUTO_START=true
- API_ENABLE_BASIC_AUTH=true
- PROMETHEUS_DISABLE_COLLECT=true
- GOTENBERG_API_BASIC_AUTH_USERNAME=$GOTENBERG_USERNAME
- GOTENBERG_API_BASIC_AUTH_PASSWORD=$GOTENBERG_PASSWORD
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
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
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
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
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 5
window: 120s
app:
image: ghcr.io/amruthpillai/reactive-resume-test:latest
networks:
- traefik_network
- reactive_resume_network
volumes:
- reactive_resume_app_data:/app/data
environment:
- APP_URL=$APP_URL
- GOTENBERG_ENDPOINT=$GOTENBERG_ENDPOINT
- GOTENBERG_USERNAME=$GOTENBERG_USERNAME
- GOTENBERG_PASSWORD=$GOTENBERG_PASSWORD
- 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
- 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://localhost:3000/api/health').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))",
]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
deploy:
mode: replicated
replicas: 2
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
order: start-first
rollback_config:
parallelism: 1
delay: 10s
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_app_data:
name: reactive_resume_app_data
+302
View File
@@ -0,0 +1,302 @@
---
title: "Changelog"
description: "List of all notable changes and updates to Reactive Resume"
rss: true
---
<Update label="v5.0.17" description="9th April 2026">
## 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).
</Update>
<Update label="v5.0.16" description="4th April 2026">
## 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 (`<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.
</Update>
<Update label="v5.0.15" description="1st April 2026">
## 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) for a smoother loading experience.
- 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.
</Update>
<Update label="v5.0.14" description="24th March 2026">
## 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)
</Update>
<Update label="v5.0.13" description="19th March 2026">
## 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
</Update>
<Update label="v5.0.12" description="17th March 2026">
## 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 robust 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
</Update>
<Update label="v5.0.10" description="24th February 2026">
## 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 `<strong>` 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 comprehensive 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.
</Update>
<Update label="v5.0.9" description="9th February 2026">
## 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.
</Update>
<Update label="v5.0.8" description="9th February 2026">
## Fixes
- Removed Passkey support from the authentication system due to provider compatibility issues.
- Updated dependencies to the latest versions.
</Update>
<Update label="v5.0.7" description="9th February 2026">
## 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.
</Update>
<Update label="v5.0.6" description="8th February 2026">
## 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.
</Update>
<Update label="v5.0.5" description="31st January 2026">
## 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.
</Update>
<Update label="v5.0.4" description="28th January 2026">
## 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).
</Update>
<Update label="v5.0.3" description="25th January 2026">
## 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.
</Update>
<Update label="v5.0.2" description="24th January 2026">
## 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.
</Update>
<Update label="v5.0.1" description="23th January 2026">
## 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 when using `getResumeScreenshot` or `printResumeAsPDF` endpoints.
</Update>
<Update label="v5.0.0" description="22th January 2026">
This release is a major overhaul of Reactive Resume. The app has been completely redesigned and rebuilt from scratch for a more intuitive, user-friendly experience.
**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
- Powerful 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
And much more! Explore the new version and share your feedback via [contact](https://amruthpillai.com/#contact) or [GitHub issues](https://github.com/amruthpillai/reactive-resume/issues).
</Update>
+67
View File
@@ -0,0 +1,67 @@
---
title: "Spotlight"
description: "A showcase of articles, videos, and social media posts from the Reactive Resume community"
---
<Note>
Have you created something that makes use of Reactive Resume, or spread the word about it in your own way? I'd love to
feature it here! Send me an email at [hello@amruthpillai.com](mailto:hello@amruthpillai.com) and I'll make sure to add
it to this page.
</Note>
---
## Articles
A collection of blog posts and articles written by the community about Reactive Resume.
<CardGroup cols={2}>
{/* Add article cards here */}
{/\* Example:
<Card title="Article Title" icon="newspaper" href="https://example.com/article">
A brief description of the article.
</Card>
*/}
</CardGroup>
<Info>No articles have been featured yet. Be the first to contribute!</Info>
---
## Videos
Video tutorials, reviews, and walkthroughs created by the community.
<CardGroup cols={2}>
{/* Add video cards here */}
{/\* Example:
<Card title="Video Title" icon="youtube" href="https://youtube.com/watch?v=...">
A brief description of the video.
</Card>
*/}
</CardGroup>
<Info>No videos have been featured yet. Be the first to contribute!</Info>
---
## Social Media
Posts and threads from social media platforms sharing experiences with Reactive Resume.
<CardGroup cols={2}>
{/* Add social media cards here */}
{/* Example:
<Card title="Post Title" icon="twitter" href="https://twitter.com/...">
A brief description of the post.
</Card>
*/}
</CardGroup>
<Info>No social media posts have been featured yet. Be the first to contribute!</Info>
+102 -160
View File
@@ -13,16 +13,12 @@ Reactive Resume is built with a modern, type-safe stack:
<CardGroup cols={2}>
<Card title="Frontend" icon="browser">
- **React 19** with TanStack Start
- **TypeScript** for type safety
- **Tailwind CSS** for styling
- **Radix UI** for accessible components
- **React 19** with TanStack Start - **TypeScript** for type safety - **Tailwind CSS** for styling - **Radix UI**
for accessible components
</Card>
<Card title="Backend" icon="server">
- **ORPC** for type-safe RPC
- **Drizzle ORM** with PostgreSQL
- **Better Auth** for authentication
- **Sharp** for image processing
- **ORPC** for type-safe RPC - **Drizzle ORM** with PostgreSQL - **Better Auth** for authentication - **Sharp** for
image processing
</Card>
</CardGroup>
@@ -49,7 +45,7 @@ flowchart TD
Database["PostgreSQL"]
Storage["File System OR S3-Compatible Storage"]
Printer["Gotenberg"]
Printer["Printer (Browserless/Chromium)"]
Router --> ORPCClient
Query --> ORPCClient
@@ -70,89 +66,61 @@ flowchart TD
### Root Level
| Directory | Purpose |
|-----------|---------|
| `src/` | Main application source code |
| `public/` | Static assets served directly |
| `locales/` | Translation files (.po format) |
| `migrations/` | Database migration files |
| `docs/` | Mintlify documentation |
| `data/` | Local data storage (fonts, uploads) |
| `scripts/` | Utility scripts |
| Directory | Purpose |
| ------------- | ----------------------------------- |
| `src/` | Main application source code |
| `public/` | Static assets served directly |
| `locales/` | Translation files (.po format) |
| `migrations/` | Database migration files |
| `docs/` | Mintlify documentation |
| `data/` | Local data storage (fonts, uploads) |
| `scripts/` | Utility scripts |
### Source Code (`src/`)
<AccordionGroup>
<Accordion title="components/" icon="cube">
Reusable React components organized by category:
- **`ui/`** — Base UI components (Button, Card, Dialog, etc.)
- **`resume/`** — Resume-specific components (sections, templates)
- **`input/`** — Form input components (ColorPicker, RichInput)
- **`layout/`** — Layout components (Sidebar, LoadingScreen)
- **`animation/`** — Animation components (Spotlight, TextMask)
- **`theme/`** — Theme management components
- **`typography/`** — Font management components
</Accordion>
<Accordion title="routes/" icon="route">
File-based routing using TanStack Router:
- **`__root.tsx`** — Root layout with providers
- **`_home/`** — Public home page routes
- **`auth/`** — Authentication routes (login, register, etc.)
- **`dashboard/`** — User dashboard routes
- **`builder/`** — Resume builder routes (the main editor)
- **`printer/`** — PDF printing route
- **`api/`** — API routes
</Accordion>
<Accordion title="integrations/" icon="plug">
Third-party service integrations:
- **`auth/`** — Better Auth client configuration
- **`drizzle/`** — Database schema and utilities
- **`orpc/`** — API router, client, and services
- **`ai/`** — AI service integrations
- **`import/`** — Resume import utilities
</Accordion>
<Accordion title="dialogs/" icon="window-maximize">
Modal dialog components:
- **`auth/`** — Authentication dialogs
- **`resume/`** — Resume management dialogs
- **`api-key/`** — API key management dialogs
- **`manager.tsx`** — Dialog manager component
- **`store.ts`** — Dialog state management (Zustand)
</Accordion>
<Accordion title="schema/" icon="file-code">
Zod schemas for validation:
- **`resume/`** — Resume data schemas
- **`icons.ts`** — Icon definitions
- **`templates.ts`** — Template definitions
</Accordion>
<Accordion title="hooks/" icon="hook">
Custom React hooks:
- `use-confirm.tsx` — Confirmation dialog hook
- `use-prompt.tsx` — Prompt dialog hook
- `use-mobile.tsx` — Mobile detection hook
- `use-safe-context.tsx` — Safe context consumption
</Accordion>
<Accordion title="utils/" icon="wrench">
Utility functions:
- `env.ts` — Environment variable validation
- `locale.ts` — Locale utilities
- `theme.ts` — Theme utilities
- `string.ts` — String manipulation
- `file.ts` — File handling utilities
</Accordion>
<Accordion title="components/" icon="cube">
Reusable React components organized by category: - **`ui/`** — Base UI components (Button, Card, Dialog, etc.) -
**`resume/`** — Resume-specific components (sections, templates) - **`input/`** — Form input components
(ColorPicker, RichInput) - **`layout/`** — Layout components (Sidebar, LoadingScreen) - **`animation/`** — Animation
components (Spotlight, TextMask) - **`theme/`** — Theme management components - **`typography/`** — Font management
components
</Accordion>
<Accordion title="routes/" icon="route">
File-based routing using TanStack Router: - **`__root.tsx`** — Root layout with providers - **`_home/`** — Public
home page routes - **`auth/`** — Authentication routes (login, register, etc.) - **`dashboard/`** — User dashboard
routes - **`builder/`** — Resume builder routes (the main editor) - **`printer/`** — PDF printing route - **`api/`**
— API routes
</Accordion>
<Accordion title="integrations/" icon="plug">
Third-party service integrations: - **`auth/`** — Better Auth client configuration - **`drizzle/`** — Database
schema and utilities - **`orpc/`** — API router, client, and services - **`ai/`** — AI service integrations -
**`import/`** — Resume import utilities
</Accordion>
<Accordion title="dialogs/" icon="window-maximize">
Modal dialog components: - **`auth/`** — Authentication dialogs - **`resume/`** — Resume management dialogs -
**`api-key/`** — API key management dialogs - **`manager.tsx`** — Dialog manager component - **`store.ts`** — Dialog
state management (Zustand)
</Accordion>
<Accordion title="schema/" icon="file-code">
Zod schemas for validation: - **`resume/`** — Resume data schemas - **`icons.ts`** — Icon definitions -
**`templates.ts`** — Template definitions
</Accordion>
<Accordion title="hooks/" icon="hook">
Custom React hooks: - `use-confirm.tsx` — Confirmation dialog hook - `use-prompt.tsx` — Prompt dialog hook -
`use-mobile.tsx` — Mobile detection hook - `use-safe-context.tsx` — Safe context consumption
</Accordion>
<Accordion title="utils/" icon="wrench">
Utility functions: - `env.ts` — Environment variable validation - `locale.ts` — Locale utilities - `theme.ts` —
Theme utilities - `string.ts` — String manipulation - `file.ts` — File handling utilities
</Accordion>
</AccordionGroup>
---
@@ -163,16 +131,14 @@ flowchart TD
Routes are automatically generated from the file structure in `src/routes/`. TanStack Router conventions:
| Pattern | Description | Example |
|---------|-------------|---------|
| `index.tsx` | Index route | `/dashboard` |
| `$param.tsx` | Dynamic parameter | `/builder/$resumeId` |
| `_layout/` | Layout group (prefix) | `_home/` |
| `__root.tsx` | Root layout | Wraps all routes |
| Pattern | Description | Example |
| ------------ | --------------------- | -------------------- |
| `index.tsx` | Index route | `/dashboard` |
| `$param.tsx` | Dynamic parameter | `/builder/$resumeId` |
| `_layout/` | Layout group (prefix) | `_home/` |
| `__root.tsx` | Root layout | Wraps all routes |
<Warning>
Never edit `src/routeTree.gen.ts` manually — it's auto-generated when you run the dev server.
</Warning>
<Warning>Never edit `src/routeTree.gen.ts` manually — it's auto-generated when you run the dev server.</Warning>
### API Layer (ORPC)
@@ -203,11 +169,11 @@ const { data } = useQuery(orpc.resume.findMany.queryOptions());
Reactive Resume uses a hybrid approach:
| Type | Tool | Use Case |
|------|------|----------|
| Server State | TanStack Query | API data, caching, sync |
| Client State | Zustand | UI state, dialogs, preferences |
| Form State | React Hook Form | Form inputs and validation |
| Type | Tool | Use Case |
| ------------ | --------------- | ------------------------------ |
| Server State | TanStack Query | API data, caching, sync |
| Client State | Zustand | UI state, dialogs, preferences |
| Form State | React Hook Form | Form inputs and validation |
### Database Schema
@@ -280,11 +246,9 @@ import { z } from "zod";
import { publicProcedure, router } from "../server";
export const myRouter = router({
hello: publicProcedure
.input(z.object({ name: z.string() }))
.handler(async ({ input }) => {
return { message: `Hello, ${input.name}!` };
}),
hello: publicProcedure.input(z.object({ name: z.string() })).handler(async ({ input }) => {
return { message: `Hello, ${input.name}!` };
}),
});
```
@@ -300,81 +264,59 @@ import { Trans } from "@lingui/react/macro";
// In component
const title = t`Welcome`;
<Trans>Click here to continue</Trans>
<Trans>Click here to continue</Trans>;
```
---
## Configuration Files
| File | Purpose |
|------|---------|
| `vite.config.ts` | Vite bundler configuration |
| `tsconfig.json` | TypeScript configuration |
| `biome.json` | Linter and formatter settings |
| `drizzle.config.ts` | Drizzle ORM configuration |
| `lingui.config.ts` | Lingui i18n configuration |
| `components.json` | shadcn/ui component configuration |
| File | Purpose |
| ------------------- | --------------------------------- |
| `vite.config.ts` | Vite bundler configuration |
| `tsconfig.json` | TypeScript configuration |
| `.oxfmtrc.json` | Formatter settings |
| `.oxlintrc.json` | Linter settings |
| `drizzle.config.ts` | Drizzle ORM configuration |
| `lingui.config.ts` | Lingui i18n configuration |
| `components.json` | shadcn/ui component configuration |
---
## Contributing Guidelines
<Steps>
<Step title="Fork & Clone">
Fork the repository on GitHub and clone your fork locally.
</Step>
<Step title="Create a Branch">
Create a feature branch from `main`:
```bash
git checkout -b feature/my-feature
```
</Step>
<Step title="Make Changes">
Implement your changes following the patterns described above.
</Step>
<Step title="Test Locally">
Ensure the app works correctly with your changes:
```bash
pnpm run dev
pnpm run lint
pnpm run typecheck
```
</Step>
<Step title="Commit & Push">
Write clear commit messages and push to your fork.
</Step>
<Step title="Open a Pull Request">
Open a PR against the main repository with a clear description of your changes.
</Step>
<Step title="Fork & Clone">Fork the repository on GitHub and clone your fork locally.</Step>
<Step title="Create a Branch">
Create a feature branch from `main`: ```bash git checkout -b feature/my-feature ```
</Step>
<Step title="Make Changes">Implement your changes following the patterns described above.</Step>
<Step title="Test Locally">
Ensure the app works correctly with your changes: ```bash pnpm run dev pnpm run lint pnpm run typecheck ```
</Step>
<Step title="Commit & Push">Write clear commit messages and push to your fork.</Step>
<Step title="Open a Pull Request">
Open a PR against the main repository with a clear description of your changes.
</Step>
</Steps>
<Note>
Make sure to read any `CONTRIBUTING.md` file in the repository for additional guidelines.
</Note>
<Note>Make sure to read any `CONTRIBUTING.md` file in the repository for additional guidelines.</Note>
---
## Need Help?
<CardGroup cols={2}>
<Card
title="GitHub Discussions"
icon="comments"
href="https://github.com/AmruthPillai/Reactive-Resume/discussions"
>
<Card title="GitHub Discussions" icon="comments" href="https://github.com/amruthpillai/reactive-resume/discussions">
Ask questions and discuss ideas with the community.
</Card>
<Card
title="GitHub Issues"
icon="bug"
href="https://github.com/AmruthPillai/Reactive-Resume/issues"
>
<Card title="GitHub Issues" icon="bug" href="https://github.com/amruthpillai/reactive-resume/issues">
Report bugs or request features.
</Card>
</CardGroup>
+59 -118
View File
@@ -4,11 +4,8 @@ description: "Set up a local development environment for Reactive Resume"
---
<Info>
**Prerequisites**:
- [Node.js](https://nodejs.org/) v20 or higher
- [pnpm](https://pnpm.io/) v10.28.0 or higher (package manager)
- [Docker](https://docs.docker.com/get-docker/) and Docker Compose
- [Git](https://git-scm.com/)
**Prerequisites**: - [Node.js](https://nodejs.org/) v20 or higher - [pnpm](https://pnpm.io/) v10.28.0 or higher
(package manager) - [Docker](https://docs.docker.com/get-docker/) and Docker Compose - [Git](https://git-scm.com/)
</Info>
This guide walks you through setting up Reactive Resume for local development. Whether you're contributing to the project or customizing it for your needs, these steps will get you up and running.
@@ -20,7 +17,7 @@ This guide walks you through setting up Reactive Resume for local development. W
<Steps>
<Step title="Clone the Repository">
```bash
git clone https://github.com/AmruthPillai/Reactive-Resume.git
git clone https://github.com/amruthpillai/reactive-resume.git
cd Reactive-Resume
```
</Step>
@@ -47,7 +44,7 @@ This guide walks you through setting up Reactive Resume for local development. W
This starts the following infrastructure services:
- **PostgreSQL** — Database (port 5432)
- **SeaweedFS** — S3-compatible storage (port 8333)
- **Gotenberg** — PDF generation service (port 4000)
- **Printer** — PDF and screenshot generation service (port 4000)
- **Mailpit** — Email testing server (SMTP on port 1025, UI on port 8025)
<Tip>
@@ -66,6 +63,10 @@ This guide walks you through setting up Reactive Resume for local development. W
# Server
APP_URL=http://localhost:3000
# Printer (required for local development)
PRINTER_APP_URL=http://host.docker.internal:3000
PRINTER_ENDPOINT=ws://localhost:4000?token=1234567890
# Database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres
@@ -79,21 +80,19 @@ This guide walks you through setting up Reactive Resume for local development. W
S3_BUCKET=reactive-resume
S3_FORCE_PATH_STYLE=true
# PDF Printer (required for local development)
PRINTER_APP_URL=http://host.docker.internal:3000
# Email (Mailpit for local development)
SMTP_HOST=localhost
SMTP_PORT=1025
```
<Note>
**PDF Generation Note**: The `PRINTER_APP_URL` variable is required when running Reactive Resume outside of Docker while the Gotenberg PDF service is running inside Docker (which is the case when using `compose.dev.yml`). Gotenberg needs to reach your local app to render resumes for PDF generation. Since Docker containers cannot access `localhost` on your host machine directly, you must set `PRINTER_APP_URL` to `http://host.docker.internal:3000`. This special hostname allows Docker containers to communicate with services running on your host machine.
**PDF Generation Note**: The `PRINTER_APP_URL` variable is required when running Reactive Resume outside of Docker while the printer service is running inside Docker (which is the case when using `compose.dev.yml`). The printer needs to reach your local app to render resumes for PDF generation. Since Docker containers cannot access `localhost` on your host machine directly, you must set `PRINTER_APP_URL` to `http://host.docker.internal:3000`. This special hostname allows Docker containers to communicate with services running on your host machine.
</Note>
<Tip>
**Email Testing**: The development stack includes [Mailpit](https://mailpit.axllent.org/), an email testing tool. All emails sent by the application will be captured and viewable at [http://localhost:8025](http://localhost:8025). No emails will actually be sent to real addresses during development.
</Tip>
</Step>
<Step title="Run Database Migrations">
@@ -121,35 +120,34 @@ Here are the most commonly used scripts during development:
### Development
| Command | Description |
|---------|-------------|
| `pnpm run dev` | Start the development server with hot reload |
| `pnpm run build` | Build the application for production |
| `pnpm run start` | Start the production server |
| `pnpm run lint` | Run Biome linter and formatter |
| `pnpm run typecheck` | Run TypeScript type checking |
| Command | Description |
| -------------------- | -------------------------------------------- |
| `pnpm run dev` | Start the development server with hot reload |
| `pnpm run build` | Build the application for production |
| `pnpm run start` | Start the production server |
| `pnpm run lint` | Run Oxlint linter and formatter |
| `pnpm run fmt` | Run Oxfmt formatter |
| `pnpm run typecheck` | Run TypeScript type checking |
### Database
| Command | Description |
|---------|-------------|
| Command | Description |
| ---------------------- | -------------------------------------------- |
| `pnpm run db:generate` | Generate migration files from schema changes |
| `pnpm run db:migrate` | Apply pending migrations |
| `pnpm run db:push` | Push schema changes directly (dev only) |
| `pnpm run db:pull` | Pull schema from existing database |
| `pnpm run db:studio` | Open Drizzle Studio (database GUI) |
| `pnpm run db:migrate` | Apply pending migrations |
| `pnpm run db:studio` | Open Drizzle Studio (database GUI) |
### Internationalization
| Command | Description |
|---------|-------------|
| Command | Description |
| ------------------------- | -------------------------------------- |
| `pnpm run lingui:extract` | Extract translatable strings from code |
### Documentation
| Command | Description |
|---------|-------------|
| `pnpm run docs` | Start the Mintlify docs development server |
| Command | Description |
| ------------------- | ------------------------------------------ |
| `pnpm run docs:dev` | Start the Mintlify docs development server |
---
@@ -211,9 +209,7 @@ This opens a web-based GUI at [https://local.drizzle.studio](https://local.drizz
pnpm run db:migrate
```
<Warning>
Always review generated migrations before applying them, especially when working with existing data.
</Warning>
<Warning>Always review generated migrations before applying them, especially when working with existing data.</Warning>
---
@@ -233,7 +229,7 @@ import { Trans } from "@lingui/react/macro";
const message = t`Hello, World!`;
// For JSX content
<Trans>Welcome to Reactive Resume</Trans>
<Trans>Welcome to Reactive Resume</Trans>;
```
### Extracting Translations
@@ -252,11 +248,12 @@ Translation files are located in the `locales/` directory in `.po` format.
### Linting & Formatting
Uses [Biome](https://biomejs.dev/) for linting and formatting:
Uses [Oxlint](https://oxlint.dev/) for linting and [Oxfmt](https://oxfmt.dev/) for formatting:
```bash
# Check and auto-fix issues
pnpm run lint
pnpm run fmt
```
### Type Checking
@@ -268,7 +265,9 @@ pnpm run typecheck
```
<Tip>
Configure your IDE to use Biome for automatic formatting on save. For VS Code, install the [Biome extension](https://marketplace.visualstudio.com/items?itemName=biomejs.biome).
Configure your IDE to use Oxlint for automatic linting and Oxfmt for automatic formatting on save. For VS Code,
install the [Oxlint extension](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode) and configure the
settings in `.vscode/settings.json`.
</Tip>
---
@@ -276,77 +275,27 @@ pnpm run typecheck
## Troubleshooting
<AccordionGroup>
<Accordion title="Port 3000 is already in use">
Another process is using port 3000. Either stop that process or start the dev server on a different port:
```bash
PORT=3001 pnpm run dev
```
</Accordion>
<Accordion title="Database connection refused">
Ensure Docker containers are running:
```bash
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.
</Accordion>
<Accordion title="S3/Storage errors">
Verify SeaweedFS is running and the bucket exists:
```bash
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
docker compose -f compose.dev.yml restart seaweedfs-create-bucket
```
</Accordion>
<Accordion title="Type errors after pulling changes">
The route tree may need regeneration. Run the dev server which auto-generates routes:
```bash
pnpm run dev
```
Or run type checking to see specific errors:
```bash
pnpm run typecheck
```
</Accordion>
<Accordion title="Uploaded images not appearing in PDF exports">
When running in development mode (Docker services + app on host), images you upload to your resume may not appear in PDF exports. This is because the printer service runs inside Docker and cannot access URLs that resolve to `localhost` on your host machine.
**Why this happens:**
The app running on your host uploads images to SeaweedFS (S3 storage) using `localhost:8333`. When Gotenberg tries to fetch these images to render the PDF, it cannot resolve `localhost` the same way your host machine does — they're on different networks.
**Solutions:**
1. **Run the entire stack in Docker** (recommended for testing PDF exports):
Use the production `compose.yml` instead of `compose.dev.yml` to run all services, including the app, on the same Docker network:
```bash
docker compose up -d
```
This ensures all services can communicate with each other seamlessly.
2. **Use publicly accessible images**:
If you need to test PDF exports while developing on the host, use images hosted on publicly accessible URLs (e.g., images already hosted online) instead of uploading local files. The printer service can fetch these without network issues.
</Accordion>
<Accordion title="Port 3000 is already in use">
Another process is using port 3000. Either stop that process or start the dev server on a different port: ```bash
PORT=3001 pnpm run dev ```
</Accordion>
<Accordion title="Database connection refused">
Ensure Docker containers are running: ```bash 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.
</Accordion>
<Accordion title="S3/Storage errors">
Verify SeaweedFS is running and the bucket exists: ```bash 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 docker compose -f compose.dev.yml restart seaweedfs_create_bucket ```
</Accordion>
<Accordion title="Type errors after pulling changes">
The route tree may need regeneration. Run the dev server which auto-generates routes: ```bash pnpm run dev ``` Or
run type checking to see specific errors: ```bash pnpm run typecheck ```
</Accordion>
</AccordionGroup>
---
@@ -354,18 +303,10 @@ pnpm run typecheck
## Next Steps
<CardGroup cols={2}>
<Card
title="Project Architecture"
icon="folder-open"
href="/contributing/architecture"
>
<Card title="Project Architecture" icon="folder-open" href="/contributing/architecture">
Deep dive into the project architecture and codebase structure.
</Card>
<Card
title="GitHub Repository"
icon="github"
href="https://github.com/AmruthPillai/Reactive-Resume"
>
<Card title="GitHub Repository" icon="github" href="https://github.com/amruthpillai/reactive-resume">
View the source code and contribute to the project.
</Card>
</CardGroup>
+39 -41
View File
@@ -12,7 +12,8 @@ Reactive Resume is used by people all around the world, and translations help ma
Reactive Resume uses [Crowdin](https://crowdin.com/) as its localization management platform. Crowdin provides a user-friendly interface where translators can contribute translations without needing to write code or work with files directly.
<Info>
The Reactive Resume Crowdin project is available at [https://crowdin.com/project/reactive-resume](https://crowdin.com/project/reactive-resume).
The Reactive Resume Crowdin project is available at
[https://crowdin.com/project/reactive-resume](https://crowdin.com/project/reactive-resume).
</Info>
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.
@@ -22,33 +23,36 @@ Once translations are submitted and approved on Crowdin, they are automatically
## Getting Started
<Steps>
<Step title="Create a Crowdin Account">
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.
<Tip>
For detailed instructions on creating an account and getting started, see Crowdin's official [For Translators](https://support.crowdin.com/for-translators/) documentation.
</Tip>
</Step>
<Step title="Join the Reactive Resume Project">
Navigate to the [Reactive Resume project on Crowdin](https://crowdin.com/project/reactive-resume) and click **Join** to become a contributor.
</Step>
<Step title="Select Your Language">
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.
</Step>
<Step title="Start Translating">
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
</Step>
<Step title="Save Your Translations">
Your translations are saved automatically as you work. Once reviewed, they'll be included in the next app release.
</Step>
<Step title="Create a Crowdin Account">
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.
<Tip>
For detailed instructions on creating an account and getting started, see Crowdin's official [For
Translators](https://support.crowdin.com/for-translators/) documentation.
</Tip>
</Step>
<Step title="Join the Reactive Resume Project">
Navigate to the [Reactive Resume project on Crowdin](https://crowdin.com/project/reactive-resume) and click **Join**
to become a contributor.
</Step>
<Step title="Select Your Language">
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.
</Step>
<Step title="Start Translating">
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
</Step>
<Step title="Save Your Translations">
Your translations are saved automatically as you work. Once reviewed, they'll be included in the next app release.
</Step>
</Steps>
---
@@ -90,12 +94,13 @@ Some technical terms (like "PDF", "URL", "JSON") are often kept in English acros
If your language is not listed in the Crowdin project, you can request it to be added.
<Warning>
Before requesting a new language, please check if it's already available in the [Crowdin project](https://crowdin.com/project/reactive-resume).
Before requesting a new language, please check if it's already available in the [Crowdin
project](https://crowdin.com/project/reactive-resume).
</Warning>
To request a new language:
1. Go to the [GitHub Issues](https://github.com/AmruthPillai/Reactive-Resume/issues) page
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"
@@ -110,7 +115,8 @@ Once approved, the language will be added to Crowdin and you can begin translati
Translations submitted on Crowdin are synced to the codebase periodically. Once merged, they will be included in the next release of Reactive Resume.
<Info>
There may be a delay between submitting translations and seeing them live in the app. This is normal and depends on the release cycle.
There may be a delay between submitting translations and seeing them live in the app. This is normal and depends on
the release cycle.
</Info>
---
@@ -137,18 +143,10 @@ Translations submitted on Crowdin are synced to the codebase periodically. Once
## Need Help?
<CardGroup cols={2}>
<Card
icon="book-open"
title="Crowdin Translator Docs"
href="https://support.crowdin.com/for-translators/"
>
<Card icon="book-open" title="Crowdin Translator Docs" href="https://support.crowdin.com/for-translators/">
Official Crowdin documentation for translators.
</Card>
<Card
icon="github"
title="GitHub Issues"
href="https://github.com/AmruthPillai/Reactive-Resume/issues"
>
<Card icon="github" title="GitHub Issues" href="https://github.com/amruthpillai/reactive-resume/issues">
Report issues or request new languages.
</Card>
</CardGroup>
+148 -126
View File
@@ -1,128 +1,150 @@
{
"$schema": "https://mintlify.com/docs.json",
"theme": "mint",
"name": "Reactive Resume",
"favicon": "/favicon.svg",
"description": "A one-of-a-kind resume builder that keeps your privacy in mind. Completely secure, customizable, portable, open-source and free forever. Try it out today!",
"seo": {
"indexing": "all",
"metatags": {
"canonical": "https://docs.rxresu.me"
}
},
"fonts": {
"heading": {
"family": "IBM Plex Sans"
},
"body": {
"family": "IBM Plex Sans"
}
},
"colors": {
"primary": "#166534",
"light": "#07C983",
"dark": "#15803D"
},
"navigation": {
"tabs": [
{
"tab": "Documentation",
"groups": [
{
"group": "Getting Started",
"pages": [
"getting-started/index",
"getting-started/quickstart",
"guides/accessing-the-previous-version",
"getting-started/changelog"
]
},
{
"group": "Account",
"pages": [
"guides/creating-an-account",
"guides/updating-your-profile",
"guides/linking-social-accounts",
"guides/deleting-your-account"
]
},
{
"group": "Resume Builder",
"pages": [
"guides/creating-your-first-resume",
"guides/choosing-a-template",
"guides/exporting-your-resume",
"guides/sharing-your-resume-publicly",
"guides/using-private-notes",
"guides/using-custom-css"
]
},
{
"group": "Security",
"pages": ["guides/setting-up-two-factor-authentication", "guides/setting-up-passkeys"]
},
{
"group": "Integrations",
"pages": ["guides/using-the-api", "guides/using-ai", "guides/json-resume-schema"]
},
{
"group": "Self-hosting",
"pages": ["guides/self-hosting-with-docker"]
},
{
"group": "Contributing",
"pages": ["contributing/architecture", "contributing/development", "contributing/translations"]
},
{
"group": "Legal",
"pages": ["legal/license", "legal/privacy-policy", "legal/terms-of-service"]
}
]
},
{
"tab": "API Reference",
"openapi": "/spec.json"
}
],
"global": {
"anchors": [
{
"icon": "link",
"anchor": "Reactive Resume",
"href": "https://rxresu.me"
},
{
"icon": "github",
"anchor": "Source Code",
"href": "https://github.com/AmruthPillai/Reactive-Resume"
}
]
}
},
"logo": {
"light": "/logo/light.svg",
"dark": "/logo/dark.svg"
},
"navbar": {
"links": [
{
"label": "Support",
"href": "https://github.com/AmruthPillai/Reactive-Resume/issues"
}
],
"primary": {
"type": "button",
"label": "Get Started",
"href": "https://rxresu.me"
}
},
"contextual": {
"options": ["copy", "view"]
},
"footer": {
"socials": {
"website": "https://rxresu.me",
"github": "https://github.com/AmruthPillai/Reactive-Resume"
}
}
"$schema": "https://mintlify.com/docs.json",
"theme": "mint",
"name": "Reactive Resume",
"favicon": "/favicon.svg",
"description": "A one-of-a-kind resume builder that keeps your privacy in mind. Completely secure, customizable, portable, open-source and free forever. Try it out today!",
"seo": {
"indexing": "all",
"metatags": {
"canonical": "https://docs.rxresu.me",
"og:image": "https://rxresu.me/opengraph/banner.jpg"
}
},
"fonts": {
"heading": {
"family": "IBM Plex Sans"
},
"body": {
"family": "IBM Plex Sans"
}
},
"colors": {
"primary": "#166534",
"light": "#07C983",
"dark": "#15803D"
},
"navigation": {
"tabs": [
{
"icon": "book",
"tab": "Documentation",
"groups": [
{
"group": "Getting Started",
"pages": [
"getting-started/index",
"getting-started/quickstart",
"guides/checking-service-status",
"guides/accessing-the-previous-version"
]
},
{
"group": "Account",
"pages": [
"guides/creating-an-account",
"guides/updating-your-profile",
"guides/linking-social-accounts",
"guides/deleting-your-account"
]
},
{
"group": "Resume Builder",
"pages": [
"guides/creating-your-first-resume",
"guides/choosing-a-template",
"guides/selecting-page-format",
"guides/moving-items-between-sections",
"guides/fitting-content-on-a-page",
"guides/adding-a-cover-letter",
"guides/exporting-your-resume",
"guides/sharing-your-resume-publicly",
"guides/using-private-notes",
"guides/using-custom-css"
]
},
{
"group": "Security",
"pages": ["guides/setting-up-two-factor-authentication", "guides/setting-up-passkeys"]
},
{
"group": "Integrations",
"pages": [
"guides/using-the-api",
"guides/using-the-patch-api",
"guides/using-the-mcp-server",
"guides/using-ai",
"guides/json-resume-schema"
]
},
{
"group": "Self-Hosting",
"pages": ["self-hosting/docker", "self-hosting/examples", "self-hosting/sso", "self-hosting/migration"]
},
{
"group": "Contributing",
"pages": ["contributing/architecture", "contributing/development", "contributing/translations"]
},
{
"group": "Community",
"pages": ["community/spotlight"]
},
{
"group": "Legal",
"pages": ["legal/license", "legal/privacy-policy", "legal/terms-of-service"]
}
]
},
{
"icon": "clock",
"tab": "Changelog",
"pages": ["changelog/index"]
},
{
"icon": "code",
"tab": "API Reference",
"openapi": "/spec.json"
}
],
"global": {
"anchors": [
{
"icon": "link",
"anchor": "Reactive Resume",
"href": "https://rxresu.me"
},
{
"icon": "github",
"anchor": "Source Code",
"href": "https://github.com/amruthpillai/reactive-resume"
}
]
}
},
"logo": {
"light": "/logo/light.svg",
"dark": "/logo/dark.svg"
},
"navbar": {
"links": [
{
"label": "Support",
"href": "https://github.com/amruthpillai/reactive-resume/issues"
}
],
"primary": {
"type": "button",
"label": "Get Started",
"href": "https://rxresu.me"
}
},
"contextual": {
"options": ["copy", "view"]
},
"footer": {
"socials": {
"website": "https://rxresu.me",
"github": "https://github.com/amruthpillai/reactive-resume"
}
}
}
-10
View File
@@ -1,10 +0,0 @@
---
title: "Changelog"
description: "List of all notable changes and updates to Reactive Resume"
rss: true
---
<Update label="v5.0.0" description="23rd January 2026">
## New Features
- Brand new UI/UX and refreshed design.
</Update>
+48 -47
View File
@@ -4,7 +4,7 @@ description: "Welcome to the documentation for Reactive Resume, a free and open-
---
<Frame>
<img src="/images/banner.jpg" alt="Reactive Resume Banner" style={{ borderRadius: '0.75rem' }} />
<img src="/images/getting-started/banner.webp" alt="Reactive Resume Banner" />
</Frame>
## What is Reactive Resume?
@@ -28,30 +28,39 @@ description: "Welcome to the documentation for Reactive Resume, a free and open-
## Key Features
<Frame>
<img src="/images/getting-started/infographic.webp" alt="An infographic of the major features of Reactive Resume" />
</Frame>
<AccordionGroup>
<Accordion title="Completely Free & Open Source" icon="code-branch">
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).
</Accordion>
<Accordion title="Multiple Templates" icon="grid-2">
Choose from a variety of professionally designed templates including Azurill, Bronzor, Chikorita, Ditto, Gengar, Glalie, Kakuna, Lapras, Leafish, Onyx, Pikachu, and Rhyhorn - each with unique layouts and styles.
</Accordion>
<Accordion title="Rich Text Editor" icon="text">
Format your content with bold, italic, links, lists, and more using our intuitive rich text editor powered by Tiptap.
</Accordion>
<Accordion title="Multi-language Support" icon="globe">
Reactive Resume supports multiple languages, making it accessible to users worldwide. Contribute translations to help us reach more people.
</Accordion>
<Accordion title="Dark Mode" icon="moon">
Work comfortably in any lighting condition with built-in dark mode support that's easy on your eyes.
</Accordion>
<Accordion title="Self-hosting Ready" icon="server">
Deploy your own instance of Reactive Resume using Docker. Keep complete control over your data and infrastructure.
</Accordion>
<Accordion title="Completely Free & Open Source" icon="code-branch">
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).
</Accordion>
<Accordion title="Multiple Templates" icon="grid-2">
Choose from a variety of professionally designed templates including Azurill, Bronzor, Chikorita, Ditto, Gengar,
Glalie, Kakuna, Lapras, Leafish, Onyx, Pikachu, and Rhyhorn - each with unique layouts and styles.
</Accordion>
<Accordion title="Rich Text Editor" icon="text">
Format your content with bold, italic, links, lists, and more using our intuitive rich text editor powered by
Tiptap.
</Accordion>
<Accordion title="Multi-language Support" icon="globe">
Reactive Resume supports multiple languages, making it accessible to users worldwide. Contribute translations to
help us reach more people.
</Accordion>
<Accordion title="Dark Mode" icon="moon">
Work comfortably in any lighting condition with built-in dark mode support that's easy on your eyes.
</Accordion>
<Accordion title="Self-hosting Ready" icon="server">
Deploy your own instance of Reactive Resume using Docker. Keep complete control over your data and infrastructure.
</Accordion>
</AccordionGroup>
## Getting Started
@@ -59,18 +68,10 @@ description: "Welcome to the documentation for Reactive Resume, a free and open-
Whether you want to use our hosted version or run your own instance, Reactive Resume has got you covered.
<CardGroup cols={2}>
<Card
title="Quickstart"
icon="rocket"
href="/getting-started/quickstart"
>
<Card title="Quickstart" icon="rocket" href="/getting-started/quickstart">
Get up and running in minutes with our hosted version or deploy your own instance.
</Card>
<Card
title="Development Setup"
icon="code"
href="/contributing/development"
>
<Card title="Development Setup" icon="code" href="/contributing/development">
Set up a local development environment to contribute or customize Reactive Resume.
</Card>
</CardGroup>
@@ -79,28 +80,28 @@ Whether you want to use our hosted version or run your own instance, Reactive Re
Reactive Resume is built with modern web technologies:
| 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 | Radix UI |
| State Management | Zustand + TanStack Query |
| 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 | Radix UI |
| State Management | Zustand + TanStack Query |
## Community & Support
<CardGroup cols={2}>
<Card title="GitHub" icon="github" href="https://github.com/AmruthPillai/Reactive-Resume">
<Card title="GitHub" icon="github" href="https://github.com/amruthpillai/reactive-resume">
Star the repo, report issues, and contribute to the project.
</Card>
<Card title="Reddit" icon="reddit" href="https://reddit.com/r/reactiveresume">
Join our Reddit community to get help and connect with other users.
</Card>
<Card title="Discord" icon="discord" href="https://discord.gg/hzwkZbyvUW">
<Card title="Discord" icon="discord" href="https://discord.gg/aSyA5ZSxpb">
Join our Discord server to get help and connect with other users.
</Card>
<Card title="Sponsor" icon="heart" href="https://opencollective.com/reactive-resume">
+106 -133
View File
@@ -23,32 +23,27 @@ Reactive Resume offers flexibility in how you want to use it. Choose the option
The easiest way to use Reactive Resume is through our cloud version at [rxresu.me](https://rxresu.me). **This service is completely free and will always remain free.**
<Steps>
<Step title="Create an Account">
Visit [rxresu.me](https://rxresu.me) and sign up for free using your email, or sign in with your GitHub or Google account.
</Step>
<Step title="Create Your First Resume">
Click the **Create Resume** button on your dashboard. Give your resume a name and select a template to get started.
</Step>
<Step title="Fill in Your Details">
Use our intuitive builder to add your:
- Personal information
- Work experience
- Education
- Skills
- Projects
- And more...
</Step>
<Step title="Export & Share">
When you're ready, export your resume as a PDF or share it via a unique public link.
</Step>
<Step title="Create an Account">
Visit [rxresu.me](https://rxresu.me) and sign up for free using your email, or sign in with your GitHub or Google
account.
</Step>
<Step title="Create Your First Resume">
Click the **Create Resume** button on your dashboard. Give your resume a name and select a template to get started.
</Step>
<Step title="Fill in Your Details">
Use our intuitive builder to add your: - Personal information - Work experience - Education - Skills - Projects -
And more...
</Step>
<Step title="Export & Share">
When you're ready, export your resume as a PDF or share it via a unique public link.
</Step>
</Steps>
<Tip>
Your resume updates in real-time as you type. The preview panel shows exactly how your final PDF will look.
</Tip>
<Tip>Your resume updates in real-time as you type. The preview panel shows exactly how your final PDF will look.</Tip>
---
@@ -64,77 +59,50 @@ Before you begin, ensure you have the following installed:
- [Docker Compose](https://docs.docker.com/compose/install/) (v2.0 or higher)
<Info>
There is <strong>no difference in features</strong> between the cloud-hosted version and the self-hosted option. Both provide the same privacy, customization, and functionality. Choose whichever deployment type suits your needs!
There is <strong>no difference in features</strong> between the cloud-hosted version and the self-hosted option. Both
provide the same privacy, customization, and functionality. Choose whichever deployment type suits your needs!
</Info>
### Quick Deployment
<Steps>
<Step title="Clone the Repository">
```bash
git clone https://github.com/AmruthPillai/Reactive-Resume.git
cd Reactive-Resume
```
</Step>
<Step title="Configure Environment Variables">
Create a `.env` file in the root directory with the following variables:
```bash
# 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)
S3_ACCESS_KEY_ID=seaweedfs
S3_SECRET_ACCESS_KEY=seaweedfs
S3_ENDPOINT=http://seaweedfs:8333
S3_BUCKET=reactive-resume
S3_FORCE_PATH_STYLE=true
```
<Warning>
For production deployments, always use strong, unique values for `AUTH_SECRET` and database credentials.
</Warning>
</Step>
<Step title="Start the Services">
```bash
docker compose up -d
```
This will start:
- **PostgreSQL** — Database for storing user data and resumes
- **SeaweedFS** — S3-compatible storage for file uploads
- **Gotenberg** — PDF generation service
- **Reactive Resume** — The main application
</Step>
<Step title="Access Your Instance">
Once all services are running, access your Reactive Resume instance at:
```
http://localhost:3000
```
</Step>
<Step title="Clone the Repository">
```bash git clone https://github.com/amruthpillai/reactive-resume.git cd Reactive-Resume ```
</Step>
<Step title="Configure Environment Variables">
Create a `.env` file in the root directory with the following variables: ```bash # 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)
S3_ACCESS_KEY_ID=seaweedfs S3_SECRET_ACCESS_KEY=seaweedfs S3_ENDPOINT=http://seaweedfs:8333
S3_BUCKET=reactive-resume S3_FORCE_PATH_STYLE=true ```
<Warning>
For production deployments, always use strong, unique values for `AUTH_SECRET` and database credentials.
</Warning>
</Step>
<Step title="Start the Services">
```bash docker compose up -d ``` This will start: - **PostgreSQL** — Database for storing user data and resumes -
**SeaweedFS** — S3-compatible storage for file uploads - **Printer** — PDF and screenshot generation service
(browserless/chromium) - **Reactive Resume** — The main application
</Step>
<Step title="Access Your Instance">
Once all services are running, access your Reactive Resume instance at: ``` http://localhost:3000 ```
</Step>
</Steps>
### Docker Compose Services
Here's what each service in the stack does:
| Service | Port | Description |
|---------|------|-------------|
| `postgres` | 5432 | PostgreSQL database for storing all application data |
| `seaweedfs` | 8333 | S3-compatible object storage for file uploads |
| `gotenberg` | 4000 | Headless Chrome service for PDF generation |
| `app` | 3000 | The main Reactive Resume application |
| Service | Port | Description |
| ----------- | ---- | ----------------------------------------------------------- |
| `postgres` | 5432 | PostgreSQL database for storing all application data |
| `seaweedfs` | 8333 | S3-compatible object storage for file uploads |
| `printer` | 4000 | Headless Chromium service for PDF and screenshot generation |
| `app` | 3000 | The main Reactive Resume application |
### Health Checks
@@ -154,51 +122,63 @@ Here's a complete list of 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 -base64 32` |
| `APP_URL` | Public URL of your Application | `https://rxresu.me` |
| `GOTENBERG_ENDPOINT` | URL of the Gotenberg PDF service | `http://gotenberg:4000` |
| Variable | Description | Example |
| ------------------ | ------------------------------ | --------------------------------------- |
| `DATABASE_URL` | PostgreSQL connection string | `postgresql://user:pass@host:5432/db` |
| `AUTH_SECRET` | Secret key for authentication | Generate with `openssl rand -base64 32` |
| `APP_URL` | Public URL of your Application | `https://rxresu.me` |
| `PRINTER_ENDPOINT` | URL of the printer service | `http://printer:3000` |
### Optional Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `PRINTER_APP_URL` | Public URL for Gotenberg to access the Application | — |
| `GOTENBERG_USERNAME` | Gotenberg Basic Auth Username (if enabled) | — |
| `GOTENBERG_PASSWORD` | Gotenberg Basic Auth Password (if enabled) | — |
| `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 | — |
| `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` |
| `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` |
| `FLAG_DEBUG_PRINTER` | Used for debugging the printer route | `false` |
| `FLAG_DISABLE_SIGNUP` | Disables new user signups | `false` |
| Variable | Description | Default |
| ------------------------------- | ----------------------------------------------------------- | ---------------------- |
| `PRINTER_APP_URL` | Public URL for the printer to access the Application | — |
| `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` |
| `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` |
| `FLAG_DEBUG_PRINTER` | Used for debugging the printer route | `false` |
| `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` |
> **Note:** Some variables are only required for using related features (OAuth, SMTP, S3, etc.) and can be left unset if unused.
<Note>
**Hybrid Setup Note**: The `PRINTER_APP_URL` variable is required when running Reactive Resume outside of Docker while the Gotenberg PDF service is running inside Docker. In this scenario, Gotenberg needs to reach your local app to render resumes for PDF generation. Since Docker containers cannot access `localhost` on your host machine directly, you must set `PRINTER_APP_URL` to `http://host.docker.internal:3000`. This special hostname allows Docker containers to communicate with services running on your host machine.
**Hybrid Setup Note**: The `PRINTER_APP_URL` variable is required when running Reactive Resume outside of Docker while
the printer service is running inside Docker. In this scenario, the printer needs to reach your local app to render
resumes for PDF generation. Since Docker containers cannot access `localhost` on your host machine directly, you must
set `PRINTER_APP_URL` to `http://host.docker.internal:3000`. This special hostname allows Docker containers to
communicate with services running on your host machine.
</Note>
<Note>
**Alternative Printer Options**: If you don't want to use browserless, you can use any headless Chrome/Chromium
instance with its remote debugging port open. For example, run `chromium --remote-debugging-port=9222` and point
`PRINTER_ENDPOINT` to that instance.
</Note>
---
@@ -206,22 +186,15 @@ Here's a complete list of environment variables you can configure:
## Next Steps
<CardGroup cols={2}>
<Card
title="Development Setup"
icon="code"
href="/contributing/development"
>
<Card title="Development Setup" icon="code" href="/contributing/development">
Set up a development environment to contribute or customize Reactive Resume.
</Card>
<Card
title="Project Architecture"
icon="folder-open"
href="/contributing/architecture"
>
<Card title="Project Architecture" icon="folder-open" href="/contributing/architecture">
Learn about the project structure and architecture.
</Card>
</CardGroup>
<Note>
**Having trouble?** Check our [GitHub Issues](https://github.com/AmruthPillai/Reactive-Resume/issues) or reach out via [email](mailto:hello@amruthpillai.com).
**Having trouble?** Check our [GitHub Issues](https://github.com/amruthpillai/reactive-resume/issues) or reach out via
[email](mailto:hello@amruthpillai.com).
</Note>
@@ -7,9 +7,7 @@ description: "Learn how to access the previous version (v4) of Reactive Resume i
If you've been using Reactive Resume for a while, you may have resumes saved in the previous version of the application. The good news is that **version 4 (v4) is still fully accessible** and will remain online for the foreseeable future.
<Info>
The previous version of Reactive Resume is available at [https://v4.rxresu.me](https://v4.rxresu.me).
</Info>
<Info>The previous version of Reactive Resume is available at [https://v4.rxresu.me](https://v4.rxresu.me).</Info>
## Why keep the old version running?
@@ -24,7 +22,8 @@ There are several reasons why v4 remains available:
The previous version will continue to run for as long as possible—until the maintainer runs out of breath or funds to keep the server active. There are no immediate plans to shut it down.
<Warning>
While v4 will remain accessible for the foreseeable future, I recommend gradually transitioning to the latest version to benefit from new features, improvements, and ongoing support.
While v4 will remain accessible for the foreseeable future, I recommend gradually transitioning to the latest version
to benefit from new features, improvements, and ongoing support.
</Warning>
## Accessing your v4 resumes
@@ -40,6 +39,7 @@ The previous version will continue to run for as long as possible—until the ma
<Tip>
If you used social login (Google, GitHub, etc.) in v4, use the same method to sign in.
</Tip>
</Step>
<Step title="Access your resumes">
@@ -57,9 +57,10 @@ If you'd like to move your resumes to the latest version of Reactive Resume, you
4. Use the import feature to upload your JSON file (select the "Reactive Resume v4 (JSON)" option)
<Info>
Your existing resumes should already be available in the new version. If you don't see them, you can manually import them using the steps above.
Your existing resumes should already be available in the new version. If you don't see them, you can manually import
them using the steps above.
</Info>
## Questions or issues?
If you encounter any problems accessing v4 or have questions about migrating your resumes, feel free to open an issue on [GitHub](https://github.com/AmruthPillai/Reactive-Resume/issues).
If you encounter any problems accessing v4 or have questions about migrating your resumes, feel free to open an issue on [GitHub](https://github.com/amruthpillai/reactive-resume/issues).
+172
View File
@@ -0,0 +1,172 @@
---
title: "Adding a cover letter"
description: "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 is a personalized document that accompanies your resume when applying for a job. It introduces you to the employer, highlights your relevant qualifications, and explains why you're a good fit for the position. Reactive Resume lets you create cover letters as custom sections, giving you full control over formatting and placement.
## Why include a cover letter?
- **Stand out**: A well-written cover letter demonstrates genuine interest in the position
- **Personalize your application**: Tailor your message to each employer and role
- **Explain gaps or transitions**: Address career changes or gaps in your resume
- **Show communication skills**: Demonstrate your ability to write clearly and professionally
## Creating a cover letter section
<Steps>
<Step title="Open the resume builder">
Navigate to your resume and open it in the builder.
</Step>
<Step title="Scroll to Custom Sections">
In the left sidebar, scroll down to find the **Custom Sections** area at the bottom.
</Step>
<Step title="Add a new custom section">
Click <Badge>Add a new custom section</Badge> to open the section creation dialog.
</Step>
<Step title="Select 'Cover Letter' as the type">
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
</Step>
<Step title="Add a cover letter item">
In your new cover letter section, click <Badge>Add a new item</Badge> to create your cover letter.
</Step>
</Steps>
## 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
<Tip>
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
```
</Tip>
### 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
<Info>
The recipient and content are both rendered directly on your resume without a section header, giving your cover letter
a clean, professional appearance.
</Info>
## Using fullscreen mode for writing
For a distraction-free writing experience, use the fullscreen mode in the rich text editor:
<Steps>
<Step title="Open the cover letter item">
Click on your cover letter item in the sidebar to open the edit dialog.
</Step>
<Step title="Expand the editor">
In either the Recipient or Content field, click the **expand icon** (arrows pointing outward) in the bottom-right
corner of the editor.
</Step>
<Step title="Write in fullscreen">
The editor will expand to nearly fill your screen, giving you a focused writing environment with all formatting tools
available.
</Step>
<Step title="Exit fullscreen">
Click the **collapse icon** or press **Escape** to return to the normal view.
</Step>
</Steps>
## Formatting options
The rich text editor supports various formatting options for your cover letter:
- **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
## Moving your cover letter to a separate page
Cover letters are typically on their own page, separate from the resume content. To achieve this:
<Steps>
<Step title="Create a second page">
In the right sidebar, go to the **Layout** section and add a new page to your resume.
</Step>
<Step title="Move the cover letter section">
Use the **Move to** feature to relocate your cover letter section to the second page.
<Tip>
See [Moving items between sections](/guides/moving-items-between-sections) for detailed instructions on how to move sections between pages.
</Tip>
</Step>
<Step title="Verify the layout">
Check the preview to ensure your cover letter appears on its own page with proper formatting.
</Step>
</Steps>
<Warning>
When exporting as PDF, pages are rendered in order. If you want the cover letter first, place it on page 1 and move
your resume content to subsequent pages.
</Warning>
## Tips for effective cover letters
<Tip>**Keep it concise**: Aim for 250-400 words. Recruiters spend about one minute reading cover letters.</Tip>
<Tip>
**Tailor each letter**: Customize your cover letter for each application. Reference specific job requirements and
company values.
</Tip>
<Tip>
**Use the same styling**: Your cover letter will inherit the fonts and colors from your resume template, ensuring a
cohesive look.
</Tip>
<Tip>
**Proofread carefully**: Spelling and grammar errors can disqualify your application. Review your letter before
exporting.
</Tip>
## 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
+97
View File
@@ -0,0 +1,97 @@
---
title: "Checking Service Status"
description: "Learn how to check the status of Reactive Resume's servers and what to do if the service is experiencing issues"
---
## Status Page
You can monitor the health and availability of Reactive Resume's servers at any time by visiting our status page:
<Card title="Status Page" icon="signal" href="https://status.rxresu.me">
View real-time server metrics including uptime, CPU usage, memory usage, and more.
</Card>
The status page provides information such as:
- **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 you notice the servers are experiencing high load or downtime, here are some recommendations:
<Steps>
<Step title="Check the status page">
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.
</Step>
<Step title="Wait and try again later">
If the servers are under heavy load, the best course of action is to wait a bit and try again later. Peak usage times can cause temporary slowdowns.
<Info>
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.
</Info>
</Step>
<Step title="Check for announcements">
For major outages or planned maintenance, announcements may be posted on our [GitHub repository](https://github.com/amruthpillai/reactive-resume).
</Step>
</Steps>
---
## A Note on Server Capacity
<Warning>
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.
</Warning>
The reality is:
- **High demand**: Thousands of users rely on this service daily
- **Limited resources**: As a free service, server capacity is constrained
- **No corporate backing**: This isn't a venture-funded startup with unlimited cloud budgets
If you find Reactive Resume valuable and want to help keep the servers running smoothly (and maybe even help scale them up), please consider supporting the project.
---
## Support the Project
Your donations directly help cover server costs, improve infrastructure, and keep Reactive Resume free for everyone.
<Card title="Donate on Open Collective" icon="heart" href="https://opencollective.com/reactive-resume">
Support Reactive Resume's development and server costs through Open Collective. Every contribution helps keep the
service running.
</Card>
<CardGroup cols={2}>
<Card title="One-time Donation" icon="gift">
Make a single contribution of any amount to help with immediate server costs.
</Card>
<Card title="Recurring Support" icon="repeat">
Become a backer with a monthly contribution to provide sustainable support.
</Card>
</CardGroup>
---
## Self-Hosting as an Alternative
If you need guaranteed uptime or want to avoid shared server limitations, you can always self-host Reactive Resume on your own infrastructure.
<Card title="Self-Hosting Guide" icon="server" href="/self-hosting/docker">
Learn how to deploy Reactive Resume on your own servers using Docker.
</Card>
Self-hosting gives you:
- **Full control** over your data and infrastructure
- **Guaranteed availability** based on your own server capacity
- **No shared resources** with other users
+72 -67
View File
@@ -13,45 +13,45 @@ Changing your resume template is simple and can be done at any time without losi
<Step title="Open your resume in the builder">
Navigate to your Dashboard and click on the resume you want to edit.
{/* TODO: Add screenshot of dashboard with resume cards */}
<Frame caption="Your resumes dashboard showing all your resume cards">
<img src="/images/choosing-template/dashboard-placeholder.jpg" alt="Dashboard showing resume cards" style={{ aspectRatio: "210/297" }} />
<Frame caption="Screenshot of your resumes dashboard showing all your resume">
<img src="/images/guides/choosing-a-template/screenshot-1.webp" alt="Screenshot of your resumes dashboard showing all your resume" />
</Frame>
</Step>
<Step title="Open the right sidebar">
In the resume builder, look for the right sidebar. This is where you'll find all the design and layout options.
{/* TODO: Add screenshot of builder with right sidebar visible */}
<Frame caption="The resume builder with the right sidebar open">
<img src="/images/choosing-template/builder-sidebar-placeholder.jpg" alt="Resume builder showing the right sidebar" style={{ aspectRatio: "210/297" }} />
</Frame>
</Step>
<Step title="Open the right sidebar">
In the resume builder, look for the right sidebar. This is where you'll find all the design and layout options.
</Step>
<Step title="Navigate to the Template section">
In the right sidebar, find and click on the **Template** section to expand it.
{/* TODO: Add screenshot of template section in sidebar */}
<Frame caption="The Template section in the right sidebar">
<img src="/images/choosing-template/template-section-placeholder.jpg" alt="Template section expanded in the sidebar" style={{ aspectRatio: "210/297" }} />
<Frame caption="Screenshot of the template section in the right sidebar">
<img src="/images/guides/choosing-a-template/screenshot-2.webp" alt="Screenshot of the template section in the right sidebar" />
</Frame>
</Step>
<Step title="Select your new template">
Browse through the available templates and click on the one you want to use. Your resume will instantly update to reflect the new design.
{/* TODO: Add screenshot showing template selection */}
<Frame caption="Selecting a new template from the available options">
<img src="/images/choosing-template/template-selection-placeholder.jpg" alt="Template selection dropdown or grid" style={{ aspectRatio: "210/297" }} />
<Frame caption="Screenshot of selecting a new template from the gallery">
<img src="/images/guides/choosing-a-template/screenshot-3.webp" alt="Screenshot of selecting a new template from the gallery" />
</Frame>
</Step>
<Step title="Review and adjust">
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.
<Frame caption="Screenshot of the resume with a new template applied">
<img src="/images/guides/choosing-a-template/screenshot-4.webp" alt="Screenshot of the resume with a new template applied" />
</Frame>
<Tip>
Different templates may display your content differently. Some templates work better with shorter content, while others are designed to handle more detailed information.
</Tip>
</Step>
</Steps>
@@ -65,13 +65,15 @@ Changing your resume template is simple and can be done at any time without losi
- **Tech/Startups**: Modern, balanced templates like Chikorita or Leafish
</Accordion>
<Accordion title="Think about content length" icon="ruler">
If you have a lot of experience to showcase, choose a template with efficient space usage. For shorter resumes, templates with more white space can make your content feel more substantial.
</Accordion>
<Accordion title="Think about content length" icon="ruler">
If you have a lot of experience to showcase, choose a template with efficient space usage. For shorter resumes,
templates with more white space can make your content feel more substantial.
</Accordion>
<Accordion title="Match your personal brand" icon="palette">
Your resume is part of your personal brand. Choose a template that reflects your personality while remaining professional and appropriate for your target roles.
</Accordion>
<Accordion title="Match your personal brand" icon="palette">
Your resume is part of your personal brand. Choose a template that reflects your personality while remaining
professional and appropriate for your target roles.
</Accordion>
<Accordion title="Test with real content" icon="file-lines">
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.
@@ -85,58 +87,63 @@ Changing your resume template is simple and can be done at any time without losi
Reactive Resume includes a variety of professionally designed templates. Each template can be further customized with your choice of colors, fonts, and layout options.
<Info>
All templates support the same features and sections. The difference is purely in how they present your information visually.
All templates support the same features and sections. The difference is purely in how they present your information
visually.
</Info>
<Columns cols={2}>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<Frame caption="Azurill">
<img src="/images/templates/azurill.jpg" alt="Azurill template preview" style={{ aspectRatio: "210/297" }} />
<img src="/images/templates/azurill.webp" alt="Azurill template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Bronzor">
<img src="/images/templates/bronzor.jpg" alt="Bronzor template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Bronzor">
<img src="/images/templates/bronzor.webp" alt="Bronzor template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Chikorita">
<img src="/images/templates/chikorita.jpg" alt="Chikorita template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Chikorita">
<img src="/images/templates/chikorita.webp" alt="Chikorita template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Ditto">
<img src="/images/templates/ditto.jpg" alt="Ditto template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Ditto">
<img src="/images/templates/ditto.webp" alt="Ditto template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Gengar">
<img src="/images/templates/gengar.jpg" alt="Gengar template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Ditgar">
<img src="/images/templates/ditgar.webp" alt="Ditgar template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Glalie">
<img src="/images/templates/glalie.jpg" alt="Glalie template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Gengar">
<img src="/images/templates/gengar.webp" alt="Gengar template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Kakuna">
<img src="/images/templates/kakuna.jpg" alt="Kakuna template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Glalie">
<img src="/images/templates/glalie.webp" alt="Glalie template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Lapras">
<img src="/images/templates/lapras.jpg" alt="Lapras template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Kakuna">
<img src="/images/templates/kakuna.webp" alt="Kakuna template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Leafish">
<img src="/images/templates/leafish.jpg" alt="Leafish template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Lapras">
<img src="/images/templates/lapras.webp" alt="Lapras template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Onyx">
<img src="/images/templates/onyx.jpg" alt="Onyx template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Leafish">
<img src="/images/templates/leafish.webp" alt="Leafish template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Pikachu">
<img src="/images/templates/pikachu.jpg" alt="Pikachu template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Onyx">
<img src="/images/templates/onyx.webp" alt="Onyx template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Pikachu">
<img src="/images/templates/pikachu.webp" alt="Pikachu template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
<Frame caption="Rhyhorn">
<img src="/images/templates/rhyhorn.jpg" alt="Rhyhorn template preview" style={{ aspectRatio: "210/297" }} />
<img src="/images/templates/rhyhorn.webp" alt="Rhyhorn template preview" style={{ aspectRatio: "210/297" }} />
</Frame>
</Columns>
</div>
---
@@ -144,13 +151,11 @@ Reactive Resume includes a variety of professionally designed templates. Each te
After selecting a template, you can customize it further:
| 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 |
| 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 |
<Tip>
For more advanced customization options, check out [Using Custom CSS](/guides/using-custom-css).
</Tip>
<Tip>For more advanced customization options, check out [Using Custom CSS](/guides/using-custom-css).</Tip>
+18 -29
View File
@@ -6,18 +6,10 @@ description: "Learn how to create an account on Reactive Resume and get started
<Steps>
<Step title="Visit the homepage">
Head over to [https://rxresu.me](https://rxresu.me) and click on the <Badge>Get Started</Badge> button.
<Frame>
<img src="/images/creating-an-account/get-started-button.png" alt="Get Started button on homepage" />
</Frame>
</Step>
<Step title="Navigate to the sign up page">
You should see a link that says <Badge>Don't have an account? Create one now →</Badge>. Click on that link to go to the sign up page and you should see a form like this:
<Frame>
<img src="/images/creating-an-account/create-account-link.png" alt="Create account link on login page" />
</Frame>
You should see a link that says <Badge>Don't have an account? Create one now →</Badge>. Click on that link to go to the sign up page and you should see a form.
</Step>
<Step title="Fill in your details">
@@ -27,14 +19,11 @@ description: "Learn how to create an account on Reactive Resume and get started
- **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
<Frame>
<img src="/images/creating-an-account/sign-up-form.png" alt="Sign up form" />
</Frame>
<Warning>
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`).
</Warning>
</Step>
<Step title="Sign up and log in">
@@ -62,10 +51,6 @@ description: "Learn how to create an account on Reactive Resume and get started
- Create your first resume
- Import an existing resume
- Manage your account settings
<Frame>
<img src="/images/creating-an-account/dashboard.png" alt="Reactive Resume dashboard" />
</Frame>
</Step>
</Steps>
@@ -87,15 +72,19 @@ description: "Learn how to create an account on Reactive Resume and get started
## Troubleshooting
<AccordionGroup>
<Accordion title="Username Already Taken">
If you see an error that your username is already taken, try a different variation. Usernames must be unique across all users.
</Accordion>
<Accordion title="Email Already Registered">
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.
</Accordion>
<Accordion title="Didn't Receive Verification Email">
Check your spam folder first. If you still don't see it, you can request a new verification email from your account settings.
</Accordion>
<Accordion title="Username Already Taken">
If you see an error that your username is already taken, try a different variation. Usernames must be unique across
all users.
</Accordion>
<Accordion title="Email Already Registered">
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.
</Accordion>
<Accordion title="Didn't Receive Verification Email">
Check your spam folder first. If you still don't see it, you can request a new verification email from your account
settings.
</Accordion>
</AccordionGroup>
+8 -3
View File
@@ -10,6 +10,7 @@ description: "Learn how to create your first resume in Reactive Resume, set a na
<Tip>
If you haven't created an account yet, follow the guide on [Creating an Account](/guides/creating-an-account).
</Tip>
</Step>
<Step title="Open the Resumes Dashboard">
@@ -18,11 +19,12 @@ description: "Learn how to create your first resume in Reactive Resume, set a na
<Info>
This is where you can create, organize, and manage multiple resumes for different roles or versions.
</Info>
</Step>
<Step title="Click “Create a new resume”">
In the Resumes Dashboard, click on the <Badge>Create a new resume</Badge> card to open the creation form.
</Step>
<Step title="Click “Create a new resume”">
In the Resumes Dashboard, click on the <Badge>Create a new resume</Badge> card to open the creation form.
</Step>
<Step title="Name your resume">
Fill in the resume name. This can be a generic name (e.g., “General Resume”) or something tied to the position you’re applying for.
@@ -30,6 +32,7 @@ description: "Learn how to create your first resume in Reactive Resume, set a na
<Tip>
If you can’t think of a name yet, click the <Badge>Magic Wand</Badge> button to generate a random name for you.
</Tip>
</Step>
<Step title="Review (or edit) the slug">
@@ -38,6 +41,7 @@ description: "Learn how to create your first resume in Reactive Resume, set a na
<Warning>
If you choose to publicly share your resume, it will be accessible at `https://rxresu.me/{username}/{slug}`.
</Warning>
</Step>
<Step title="Add tags (optional)">
@@ -46,6 +50,7 @@ description: "Learn how to create your first resume in Reactive Resume, set a na
<Info>
You can filter resumes by tags later from the Dashboard.
</Info>
</Step>
<Step title="Open the resume in the builder">
+6 -4
View File
@@ -8,9 +8,10 @@ description: "Learn how to permanently delete your Reactive Resume account and a
Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials.
</Step>
<Step title="Navigate to Danger Zone">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section, click on <Badge>Danger Zone</Badge>.
</Step>
<Step title="Navigate to Danger Zone">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section,
click on <Badge>Danger Zone</Badge>.
</Step>
<Step title="Type the confirmation text">
On the Danger Zone page, type <Badge>delete</Badge> into the confirmation input.
@@ -18,6 +19,7 @@ description: "Learn how to permanently delete your Reactive Resume account and a
<Info>
The <Badge>Delete Account</Badge> button will stay disabled until the confirmation text matches exactly.
</Info>
</Step>
<Step title="Delete your account">
@@ -26,10 +28,10 @@ description: "Learn how to permanently delete your Reactive Resume account and a
<Warning>
This action cannot be undone. All your data will be permanently deleted.
</Warning>
</Step>
<Step title="You will be signed out">
After deletion completes, you will be signed out and redirected to the homepage.
</Step>
</Steps>
File diff suppressed because one or more lines are too long
+167
View File
@@ -0,0 +1,167 @@
---
title: "Fitting content on a page"
description: "Learn how to reorganize and format your resume content to fit within a single page, whether you're using A4 or Letter format."
---
When your resume content overflows the page, Reactive Resume displays a warning just below the page. This guide explains how to reorganize and adjust your content so everything fits within your chosen page format.
<Frame caption="Screenshot of the overflow warning message in the resume builder">
<img
src="/images/guides/fitting-content-on-a-page/screenshot-1.webp"
alt="Screenshot of the overflow warning message in the resume builder"
/>
</Frame>
<Warning>
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.
</Warning>
## Quick fixes
Here are several ways to fit your content within a page, ordered from simplest to most involved.
### 1. Switch to Free-Form format
If you don't plan on printing your resume, the simplest solution is to switch to **Free-Form** format. Free-Form creates a single continuous page with no height limit, eliminating overflow concerns entirely.
With Free-Form:
- Your entire resume renders as one seamless document
- No awkward page breaks to manage
- ATS parsers and AI scanners can still read your content perfectly
- You focus on content, not arbitrary page constraints
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).
<Tip>
Since most resumes are viewed digitally today, Free-Form is often the best choice unless you specifically need to
print physical copies.
</Tip>
### 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.
<Tip>Read each bullet point and ask: "Does this help me get an interview?" If not, cut it.</Tip>
### 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.
<Frame caption="Screenshot of the columns setting for a section">
<img
src="/images/guides/fitting-content-on-a-page/screenshot-2.webp"
alt="Screenshot of the columns setting for a section"
/>
</Frame>
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 |
<Info>
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.
</Info>
### 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).
<Tip>
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.
</Tip>
### 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 |
<Info>
**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.
</Info>
### 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; you don't need to list them
- **Older certifications** — Keep only those 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). The best resumes fit their content naturally rather than forcing everything into a cramped layout.
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
<Tip>
Use the live preview to see changes as you make them. Small adjustments add up—reducing font size by 0.5pt combined
with slightly smaller margins can recover enough space for several lines of content.
</Tip>
## 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.
File diff suppressed because it is too large Load Diff
+10 -7
View File
@@ -8,13 +8,15 @@ description: "Learn how to connect or disconnect social sign-in providers like G
Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials.
</Step>
<Step title="Navigate to Authentication settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section, click on the <Badge>Authentication</Badge> link.
</Step>
<Step title="Navigate to Authentication settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section,
click on the <Badge>Authentication</Badge> link.
</Step>
<Step title="Find the social provider you want to link">
On the Authentication page, you may see sections for one or more providers (for example, <Badge>Google</Badge> or <Badge>GitHub</Badge>), depending on what is enabled on your instance.
</Step>
<Step title="Find the social provider you want to link">
On the Authentication page, you may see sections for one or more providers (for example, <Badge>Google</Badge> or{" "}
<Badge>GitHub</Badge>), depending on what is enabled on your instance.
</Step>
<Step title="Connect your account">
Click the <Badge>Connect</Badge> 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.
@@ -22,6 +24,7 @@ description: "Learn how to connect or disconnect social sign-in providers like G
<Info>
After a successful link, the button will change to <Badge>Disconnect</Badge>.
</Info>
</Step>
<Step title="Disconnect a provider (optional)">
@@ -30,6 +33,6 @@ description: "Learn how to connect or disconnect social sign-in providers like G
<Warning>
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.
</Warning>
</Step>
</Steps>
@@ -0,0 +1,144 @@
---
title: "Moving items between sections"
description: "Learn how to move resume items from one section to another, or to a different page, to better organize your content and split lengthy sections across multiple pages."
---
If you have a long work history or extensive project list, you may want to split items across multiple pages or reorganize them into different sections. The **Move to** feature lets you do exactly that—quickly relocate any item to another section or page with just a few clicks.
## Why move items?
- **Split lengthy sections**: If your Experience section spans more than one page, you can move older roles to a custom section on page 2.
- **Reorganize content**: Move a project from "Projects" to a custom "Open Source" section, or relocate a skill to a different grouping.
- **Fine-tune page layout**: Control exactly which items appear on which page for a polished, balanced resume.
## How to move an item
<Steps>
<Step title="Open the resume builder">
Navigate to your resume and open it in the builder.
<Info>
Make sure you have at least one item in a section (e.g., an experience entry, project, or skill) before proceeding.
</Info>
</Step>
<Step title="Locate the item you want to move">
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.
<Frame caption="Screenshot of the left sidebar with an expanded section containing multiple items">
<img src="/images/guides/moving-items-between-sections/screenshot-1.webp" alt="Screenshot of the left sidebar with an expanded section containing multiple items" />
</Frame>
</Step>
<Step title="Open the item dropdown menu">
Each item has a **dropdown menu** (three-dot icon or chevron) on the right side. Click this icon to reveal the available actions.
<Frame caption="Screenshot of the dropdown menu icon on a section item">
<img src="/images/guides/moving-items-between-sections/screenshot-2.webp" alt="Screenshot of the dropdown menu icon on a section item" />
</Frame>
</Step>
<Step title="Hover over 'Move to'">
In the dropdown menu, hover over or click the <Badge>Move to</Badge> option. This will open a submenu showing all
available destinations.
</Step>
<Step title="Select a destination">
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.
<Frame caption="Screenshot of the 'Move to' submenu with destination options">
<img src="/images/guides/moving-items-between-sections/screenshot-3.webp" alt="Screenshot of the 'Move to' submenu with destination options" />
</Frame>
<Tip>
If a custom section of the same type doesn't exist on your target page, Reactive Resume will **automatically create one** for you. This makes it easy to split sections across pages without manual setup.
</Tip>
</Step>
<Step title="Verify the move">
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
<Frame caption="Screenshot of the item in its new location">
<img src="/images/guides/moving-items-between-sections/screenshot-4.webp" alt="Screenshot of the item in its new location" />
</Frame>
</Step>
</Steps>
## Example: Splitting Work Experience across pages
A common use case is when your work history is too long to fit on a single page. Here's how to handle it:
<Steps>
<Step title="Identify items to move">
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.
</Step>
<Step title="Move older positions">
For each older position you want to relocate:
1. Open the item's dropdown menu
2. Click <Badge>Move to</Badge>
3. Select **Page 2** (or the appropriate page)
<Info>
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.
</Info>
</Step>
<Step title="Review the result">
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
{/* TODO: Add screenshot showing a resume with Experience split across page 1 and page 2 */}
</Step>
</Steps>
## Tips for organizing multi-page resumes
<Tip>
**Keep it logical**: Maintain chronological order within each page. Move complete job entries rather than splitting a
single role across pages.
</Tip>
<Tip>
**Use custom section names**: After moving items to a new custom section, you can rename it (e.g., "Earlier
Experience" or "Additional Projects") to provide context for recruiters.
</Tip>
<Warning>
Moving items reorganizes your content but doesn't affect the data itself. You can always move items back or to
different sections as needed.
</Warning>
## 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, you may need to recreate it in the desired section.
### 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.
+162
View File
@@ -0,0 +1,162 @@
---
title: "Selecting the right page format"
description: "Learn about the three page format options in Reactive Resume—A4, Letter, and Free-Form—and choose the best one for your needs."
---
Reactive Resume offers three page format options: **A4**, **Letter**, and **Free-Form**. Each format affects how your resume is rendered and exported as a PDF. This guide explains the differences and helps you choose the right format for your situation.
## 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 a modern format designed for digital-first resumes. Instead of conforming to a physical page size, Free-Form produces a **single continuous page** with no height limit. The width matches A4 (210mm), but the height extends as needed to fit all your content.
| Property | Value |
| -------- | ------------- |
| Width | 210mm (794px) |
| Height | Unlimited |
<Info>
With Free-Form, there are no page breaks. Your entire resume renders as one seamless document, regardless of how much
content you have.
</Info>
## Why Free-Form exists
The reality of modern job applications is that **nobody prints resumes anymore**. Your resume is almost always viewed digitally—on a screen, in an applicant tracking system (ATS), or parsed by AI-powered screening tools.
When your resume is processed digitally:
- **ATS parsers** extract text content 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 entire content regardless of page height
Since physical page constraints no longer matter for most use cases, Free-Form lets you focus on content rather than worrying about fitting everything into arbitrary page limits.
<Tip>
If you don't plan on printing your resume, Free-Form is often the simplest choice. You never have to worry about
content overflowing or awkward page breaks.
</Tip>
## How to change your page format
<Steps>
<Step title="Open your resume in the builder">
Navigate to your Dashboard and click on the resume you want to edit.
</Step>
<Step title="Open the right sidebar">
In the resume builder, look for the right sidebar on the right side of the screen.
</Step>
<Step title="Navigate to the Page section">
In the right sidebar, find and click on the **Page** section to expand it.
</Step>
<Step title="Select your format">
Find the **Format** dropdown and select your preferred option: A4, Letter, or Free-Form.
<Frame caption="Screenshot of the Format dropdown in the Page section">
<img src="/images/guides/selecting-page-format/screenshot-1.webp" alt="Screenshot of the Format dropdown in the Page section" />
</Frame>
</Step>
<Step title="Review the preview">
Your resume preview updates immediately to reflect the new format. Check that your content displays correctly.
</Step>
</Steps>
## Choosing the right format
Use this quick reference to decide which format fits your needs:
| 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 |
<Warning>
If you switch from Free-Form to A4 or Letter, your content will be split across multiple pages. Review the result
carefully to ensure page breaks don't occur in awkward places.
</Warning>
## Example PDFs
Download these sample resumes to see how different formats affect the final PDF output:
<CardGroup cols={1}>
<Card
arrow
horizontal
title="A4 Format Example"
icon="file-pdf"
href="https://github.com/user-attachments/files/24849548/a4.pdf"
>
A sample resume in A4 format showing traditional page breaks and constraints.
</Card>
<Card
arrow
horizontal
title="Free-Form Example"
icon="file-lines"
href="https://github.com/user-attachments/files/24849552/free-form.pdf"
>
A sample resume in Free-Form format showing a continuous single-page layout.
</Card>
</CardGroup>
## Frequently asked questions
<AccordionGroup>
<Accordion title="Does Free-Form work with ATS systems?">
Yes. ATS systems parse the text content of your PDF, not the page dimensions. Free-Form resumes are fully compatible with applicant tracking systems.
</Accordion>
<Accordion title="Can I switch formats after creating my resume?">
Absolutely. You can change the format at any time from the Page section in the right sidebar. Your content is
preserved—only the layout changes.
</Accordion>
<Accordion title="What if a job posting asks for a 'one-page resume'?">
If the employer specifically requests a one-page resume and expects a traditional format, use A4 or Letter and ensure
your content fits within a single page. See [Fitting content on a page](/guides/fitting-content-on-a-page) for tips.
</Accordion>
<Accordion title="Does Free-Form affect the file size?">
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.
</Accordion>
<Accordion title="Which format should I use for LinkedIn?">
LinkedIn doesn't display uploaded resumes in their original format—it extracts the content. Free-Form works perfectly for LinkedIn uploads.
</Accordion>
</AccordionGroup>
+22 -10
View File
@@ -3,22 +3,33 @@ title: "Setting up passkeys"
description: "Learn how to register passkeys (WebAuthn) to sign in securely using biometrics or your device PIN"
---
<Warning>
<strong>Passkeys Temporarily Disabled:</strong> Passkey registration and sign-in are currently unavailable in Reactive Resume due to an upstream issue with our authentication provider. We are closely monitoring the situation and will re-enable passkeys once it is resolved.
For more details and technical updates, see the <a href="https://github.com/better-auth/better-auth/issues/7463" target="_blank" rel="noopener">GitHub issue #7463</a>.
</Warning>
---
<Steps>
<Step title="Sign in to the dashboard">
Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials.
</Step>
<Step title="Navigate to Authentication settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section, click on the <Badge>Authentication</Badge> link.
</Step>
<Step title="Navigate to Authentication settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section,
click on the <Badge>Authentication</Badge> link.
</Step>
<Step title="Register a new device">
In the <Badge>Passkeys</Badge> section, click on the <Badge>Register New Device</Badge> button.
</Step>
<Step title="Register a new device">
In the <Badge>Passkeys</Badge> section, click on the <Badge>Register New Device</Badge> button.
</Step>
<Step title="Name your passkey">
You'll be prompted to enter a name for the passkey. Use something descriptive so you can recognize it later (for example, “MacBook Touch ID” or “iPhone Face ID”).
</Step>
<Step title="Name your passkey">
You'll be prompted to enter a name for the passkey. Use something descriptive so you can recognize it later (for
example, “MacBook Touch ID” or “iPhone Face ID”).
</Step>
<Step title="Complete the passkey prompt">
Your browser or device will show a passkey prompt (WebAuthn). Follow the on-screen instructions to register your passkey using your biometric (Face ID / Touch ID / fingerprint) or device PIN.
@@ -26,6 +37,7 @@ description: "Learn how to register passkeys (WebAuthn) to sign in securely usin
<Info>
Passkeys are tied to your device (or password manager) and are a more secure alternative to passwords.
</Info>
</Step>
<Step title="Manage passkeys (optional)">
@@ -34,6 +46,6 @@ description: "Learn how to register passkeys (WebAuthn) to sign in securely usin
<Warning>
Deleting a passkey cannot be undone. After deletion, you won't be able to sign in using that passkey anymore.
</Warning>
</Step>
</Steps>
@@ -10,6 +10,7 @@ description: "Learn how to enable two-factor authentication (2FA) to add an extr
<Warning>
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.
</Warning>
</Step>
<Step title="Sign in to the dashboard">
@@ -18,15 +19,18 @@ description: "Learn how to enable two-factor authentication (2FA) to add an extr
<Tip>
If you haven't created an account yet, follow the guide on [Creating an Account](/guides/creating-an-account).
</Tip>
</Step>
<Step title="Navigate to Authentication settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section, click on the <Badge>Authentication</Badge> link.
</Step>
<Step title="Navigate to Authentication settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section,
click on the <Badge>Authentication</Badge> link.
</Step>
<Step title="Click on Enable 2FA">
On the Authentication page, find the <Badge>Two-Factor Authentication</Badge> section and click on the <Badge>Enable 2FA</Badge> button.
</Step>
<Step title="Click on Enable 2FA">
On the Authentication page, find the <Badge>Two-Factor Authentication</Badge> section and click on the{" "}
<Badge>Enable 2FA</Badge> button.
</Step>
<Step title="Enter your password">
You will be asked to re-enter your password to authenticate that it's really you. Enter your password and click continue.
@@ -34,6 +38,7 @@ description: "Learn how to enable two-factor authentication (2FA) to add an extr
<Info>
This password verification step ensures that only authorized users can enable two-factor authentication on your account.
</Info>
</Step>
<Step title="Scan the QR code">
@@ -51,6 +56,7 @@ description: "Learn how to enable two-factor authentication (2FA) to add an extr
<Info>
You can also copy the secret key above the QR code and paste it into your authenticator app if you prefer manual entry.
</Info>
</Step>
<Step title="Save your backup codes">
@@ -59,6 +65,7 @@ description: "Learn how to enable two-factor authentication (2FA) to add an extr
<Warning>
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.
</Warning>
</Step>
<Step title="Sign in with 2FA">
@@ -67,5 +74,6 @@ description: "Learn how to enable two-factor authentication (2FA) to add an extr
<Tip>
If you've lost access to your authenticator device, you can use one of your backup codes to sign in. Remember that each backup code can only be used once.
</Tip>
</Step>
</Steps>
+48 -44
View File
@@ -29,13 +29,11 @@ Reactive Resume lets you share your resume via a **public URL** that anyone can
Navigate to your resume in the resume builder.
</Step>
<Step title="Go to the Sharing section">
In the **right sidebar**, select **Sharing**.
</Step>
<Step title="Go to the Sharing section">In the **right sidebar**, select **Sharing**.</Step>
<Step title="Toggle 'Allow Public Access'">
Turn on the **Allow Public Access** switch. Once enabled, your resume will be accessible via its public URL.
</Step>
<Step title="Toggle 'Allow Public Access'">
Turn on the **Allow Public Access** switch. Once enabled, your resume will be accessible via its public URL.
</Step>
<Step title="Copy your public URL">
Your public URL is displayed below the toggle. It follows this format:
@@ -45,11 +43,13 @@ Reactive Resume lets you share your resume via a **public URL** that anyone can
```
Click the **copy** button to copy the URL to your clipboard.
</Step>
</Steps>
<Tip>
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.
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.
</Tip>
## How the public URL works
@@ -62,7 +62,8 @@ When someone visits your public resume URL:
4. **Views are tracked** - Each visit is counted in your resume statistics (see below)
<Info>
Changes you make in the builder are reflected immediately on the public URL. There's no separate "publish" step—your public resume is always in sync.
Changes you make in the builder are reflected immediately on the public URL. There's no separate "publish" step—your
public resume is always in sync.
</Info>
## Tracking views and downloads
@@ -75,15 +76,16 @@ In the resume builder, open the **right sidebar** and select **Statistics**.
You'll see:
| Metric | Description |
|--------|-------------|
| **Views** | Number of times your public resume page was visited |
| **Last viewed** | The date when your resume was last viewed |
| **Downloads** | Number of times your resume was downloaded (via the public page) |
| **Last downloaded** | The date when your resume was last downloaded |
| Metric | Description |
| ------------------- | ---------------------------------------------------------------- |
| **Views** | Number of times your public resume page was visited |
| **Last viewed** | The date when your resume was last viewed |
| **Downloads** | Number of times your resume was downloaded (via the public page) |
| **Last downloaded** | The date when your resume was last downloaded |
<Info>
Statistics are only tracked when your resume is **public**. If you turn off public access, tracking pauses but your existing stats are preserved.
Statistics are only tracked when your resume is **public**. If you turn off public access, tracking pauses but your
existing stats are preserved.
</Info>
### What counts as a view?
@@ -95,7 +97,8 @@ A view is counted each time someone loads your public resume page. This includes
- Search engine visits (if your resume is indexed)
<Note>
Only **you** can see your resume's statistics. Visitors to your public URL cannot see how many views or downloads your resume has.
Only **you** can see your resume's statistics. Visitors to your public URL cannot see how many views or downloads your
resume has.
</Note>
## Password protecting your resume
@@ -115,13 +118,11 @@ When password protection is enabled:
First, make sure **Allow Public Access** is turned on in the **Sharing** section.
</Step>
<Step title="Click 'Set Password'">
Below the public URL, click the **Set Password** button.
</Step>
<Step title="Click 'Set Password'">Below the public URL, click the **Set Password** button.</Step>
<Step title="Enter your password">
Type a password (6-64 characters) and confirm. This password will be required to view your resume.
</Step>
<Step title="Enter your password">
Type a password (6-64 characters) and confirm. This password will be required to view your resume.
</Step>
<Step title="Share the password separately">
Share the password with your intended audience through a secure channel (e.g., direct message, email).
@@ -149,21 +150,21 @@ Your resume will become accessible to anyone with the public URL.
Add your public resume URL to your LinkedIn profile's **Featured** section or **Contact Info**. Recruiters can view your detailed resume directly.
</Accordion>
<Accordion title="Email signature" icon="envelope">
Include your resume link in your email signature. Anyone you correspond with can quickly access your resume.
</Accordion>
<Accordion title="Email signature" icon="envelope">
Include your resume link in your email signature. Anyone you correspond with can quickly access your resume.
</Accordion>
<Accordion title="Portfolio website" icon="globe">
Embed or link to your resume from your personal website. The link always shows your latest resume.
</Accordion>
<Accordion title="Portfolio website" icon="globe">
Embed or link to your resume from your personal website. The link always shows your latest resume.
</Accordion>
<Accordion title="Job applications" icon="briefcase">
Some applications ask for a link to your resume. Your public URL is a professional alternative to file uploads.
</Accordion>
<Accordion title="Job applications" icon="briefcase">
Some applications ask for a link to your resume. Your public URL is a professional alternative to file uploads.
</Accordion>
<Accordion title="Networking events" icon="users">
Share your resume URL via QR code or NFC. Update your resume before the event and everyone gets the latest version.
</Accordion>
<Accordion title="Networking events" icon="users">
Share your resume URL via QR code or NFC. Update your resume before the event and everyone gets the latest version.
</Accordion>
<Accordion title="Confidential job search" icon="lock">
Use password protection to share your resume only with specific recruiters while keeping it hidden from your current employer.
@@ -185,7 +186,8 @@ When public access is disabled:
- Password protection settings are preserved
<Tip>
If you only want to temporarily hide your resume, consider using password protection instead of disabling public access entirely. This way, your URL remains active for people who have the password.
If you only want to temporarily hide your resume, consider using password protection instead of disabling public
access entirely. This way, your URL remains active for people who have the password.
</Tip>
## Frequently asked questions
@@ -195,17 +197,19 @@ When public access is disabled:
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 on your resume card in the dashboard and select "Update". The username is set in your account settings.
</Accordion>
<Accordion title="Will search engines index my public resume?">
Public resumes may be indexed by search engines. If you want to prevent indexing, use password protection or keep your resume private.
</Accordion>
<Accordion title="Will search engines index my public resume?">
Public resumes may be indexed by search engines. If you want to prevent indexing, use password protection or keep your
resume private.
</Accordion>
<Accordion title="Do views from my own visits count?">
Views are only counted when someone visits your public resume URL while not logged in. Visits made while you're logged in to your account are not included in the view statistics.
</Accordion>
<Accordion title="Do views from my own visits count?">
Views are only counted when someone visits your public resume URL while not logged in. Visits made while you're logged
in to your account are not included in the view statistics.
</Accordion>
<Accordion title="Can I see who viewed my resume?">
No, Reactive Resume only tracks view and download counts, not the identity of visitors. This protects visitor privacy.
</Accordion>
<Accordion title="Can I see who viewed my resume?">
No, Reactive Resume only tracks view and download counts, not the identity of visitors. This protects visitor privacy.
</Accordion>
<Accordion title="What happens if I change my username?">
Your public URL will change to reflect the new username. Old URLs will stop working immediately. You might need to update any links you've shared.
+7 -3
View File
@@ -10,11 +10,13 @@ description: "Learn how to update your profile information including your name,
<Tip>
If you haven't created an account yet, follow the guide on [Creating an Account](/guides/creating-an-account).
</Tip>
</Step>
<Step title="Navigate to Profile settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section, click on the <Badge>Profile</Badge> link.
</Step>
<Step title="Navigate to Profile settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section,
click on the <Badge>Profile</Badge> link.
</Step>
<Step title="Update your information">
On the Profile page, you can update the following information:
@@ -26,6 +28,7 @@ description: "Learn how to update your profile information including your name,
<Warning>
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.
</Warning>
</Step>
<Step title="Verify email changes (if applicable)">
@@ -34,5 +37,6 @@ description: "Learn how to update your profile information including your name,
<Tip>
Make sure to check your spam folder if you don't see the verification email in your inbox. The verification link is required to complete the email address change.
</Tip>
</Step>
</Steps>
+15 -10
View File
@@ -8,9 +8,10 @@ description: "Learn how to configure an AI provider and API key for AI-assisted
Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials.
</Step>
<Step title="Navigate to Artificial Intelligence settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section, click on <Badge>Artificial Intelligence</Badge>.
</Step>
<Step title="Navigate to Artificial Intelligence settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section,
click on <Badge>Artificial Intelligence</Badge>.
</Step>
<Step title="How your data is stored and sent">
When you configure your AI provider settings on this page, all information (such as the API key and model) is stored locally in your browser and **not** in our database.
@@ -20,6 +21,7 @@ description: "Learn how to configure an AI provider and API key for AI-assisted
</Info>
However, whenever you use an AI-assisted feature (such as text generation), these credentials need to be sent to the server **temporarily and only for the duration of your request**. This is required to connect with the AI provider on your behalf. See below for a deeper explanation.
</Step>
<Step title="Choose a provider">
@@ -29,11 +31,13 @@ description: "Learn how to configure an AI provider and API key for AI-assisted
- **Google Gemini**
- **Anthropic Claude**
- **Ollama** (coming soon)
</Step>
<Step title="Enter a model name">
In the <Badge>Model</Badge> field, enter the model you want to use (for example, <code>gpt-5.2</code>, <code>claude-4.5-opus</code>, or <code>gemini-3-flash</code>).
</Step>
<Step title="Enter a model name">
In the <Badge>Model</Badge> field, enter the model you want to use (for example, <code>gpt-5.2</code>,{" "}
<code>claude-4.5-opus</code>, or <code>gemini-3-flash</code>).
</Step>
<Step title="Paste your API key">
In the <Badge>API Key</Badge> field, paste your provider API key.
@@ -41,6 +45,7 @@ description: "Learn how to configure an AI provider and API key for AI-assisted
<Warning>
Treat this key like a password. Anyone with it can use your provider account and may incur costs.
</Warning>
</Step>
<Step title="Verify it's enabled">
@@ -49,12 +54,13 @@ description: "Learn how to configure an AI provider and API key for AI-assisted
<Tip>
If the status shows <Badge>Disabled</Badge>, double-check that all three fields are filled in.
</Tip>
</Step>
</Steps>
## Why AI requests are sent through our server
Most AI providers (like OpenAI, Gemini, or Anthropic) block requests that come directly from the browser due to something called **CORS** ("Cross-Origin Resource Sharing"), a security mechanism built into web browsers.
Most AI providers (like OpenAI, Gemini, or Anthropic) block requests that come directly from the browser due to something called **CORS** ("Cross-Origin Resource Sharing"), a security mechanism built into web browsers.
**What is CORS?**
CORS is a browser feature that prevents web pages from making requests to a different domain than the one that served the web page, unless that domain explicitly allows it. Most AI providers do not allow browser-based requests from random websites, primarily for security and abuse prevention.
@@ -62,11 +68,10 @@ CORS is a browser feature that prevents web pages from making requests to a diff
Because of this restriction, the app has to **forward your AI requests (along with your credentials) through our server**, which then contacts the AI provider and returns the response to your browser. **Your credentials are not stored on our server; they are only used to make the request you initiated, and are not logged or retained.**
<Info>
If you're curious or would like to audit how your AI requests are forwarded, you can review the code yourself.
See the relevant implementation in <code>src/integrations/orpc/router/ai.ts</code> within the codebase.
If you're curious or would like to audit how your AI requests are forwarded, you can review the code yourself. See the
relevant implementation in <code>src/integrations/orpc/router/ai.ts</code> within the codebase.
</Info>
---
### Do you know a workaround?
+26 -33
View File
@@ -9,7 +9,14 @@ The **Custom CSS** panel lets you write your own CSS rules to change how your re
- **Live updates**: your changes are applied immediately as you type.
- **Auto-save**: there is no “Save” button—your CSS is saved automatically when it changes.
- **Scoped styling (mostly)**: to avoid affecting the rest of the app, your CSS is *usually* scoped to the resume preview.
- **Scoped styling (mostly)**: to avoid affecting the rest of the app, your CSS is _usually_ scoped to the resume preview.
<Frame caption="Screenshot of the Custom CSS section in the right sidebar">
<img
src="/images/guides/using-custom-css/screenshot-1.webp"
alt="Screenshot of the Custom CSS section in the right sidebar"
/>
</Frame>
## Where to find it
@@ -54,30 +61,32 @@ Example:
### Formatting tip (to avoid scoping edge-cases)
Keep each rule’s selector on **one line**, for example:
Keep each rule's selector on **one line**, for example:
```css
.page-section-experience .section-item-title { font-weight: 700; }
.page-section-experience .section-item-title {
font-weight: 700;
}
```
Avoid splitting a selector across multiple lines unless you’ve confirmed it behaves as expected.
Avoid splitting a selector across multiple lines unless you've confirmed it behaves as expected.
## Finding the right selectors
### Use autocomplete in the editor
In the Custom CSS editor, type a `.` (dot). You’ll get suggestions for commonly-used class selectors, including:
In the Custom CSS editor, type a `.` (dot). You'll get suggestions for commonly-used class selectors, including:
- **Page-level**: `.page`, `.page-content`, `.page-header`, `.page-basics`, `.page-main`, `.page-sidebar`, `.page-picture`
- **Section-level**: `.page-section`, `.section-content`
- **Section types**: `.page-section-experience`, `.page-section-education`, `.page-section-projects`, etc.
- **Generic item building blocks**: `.section-item`, `.section-item-header`, `.section-item-title`, `.section-item-description`, `.section-item-metadata`, `.section-item-link`, etc.
- **Generic item building blocks**: `.section-item`, `.section-item-header`, `.section-item-title`, `.section-item-description`, `.section-item-metadata`, `.section-item-website`, etc.
- **Per-section item selectors**: `.experience-item`, `.skills-item`, `.profiles-item`, etc.
- **Template wrapper**: `.template-azurill`, `.template-onyx`, `.template-gengar`, etc.
### Stable “starter selectors”
If you’re not sure where to start, these are usually safe:
If you're not sure where to start, these are usually safe:
- `.page` (the resume page container)
- `.page-section` (each resume section)
@@ -194,11 +203,11 @@ Example (tighten spacing without changing your layout settings):
### 5) Style links like a “chip” (useful for project links)
```css
.section-item-link a {
.section-item-website a {
display: inline-block;
padding: 2pt 6pt;
padding: 3pt 9pt;
border-radius: 999pt;
border: 1pt solid color-mix(in srgb, var(--page-primary-color) 45%, transparent);
border: 2pt solid color-mix(in srgb, var(--page-primary-color) 45%, transparent);
text-decoration: none;
}
```
@@ -241,40 +250,24 @@ Example (tighten spacing without changing your layout settings):
}
```
### 9) Highlight a specific section (example: Experience)
### 9) Highlight a specific section (example: Profiles)
```css
.page-section-experience {
background: color-mix(in srgb, var(--page-primary-color) 6%, transparent);
.page-section-profiles {
background: color-mix(in srgb, var(--page-primary-color) 10%, transparent);
border-radius: 8pt;
padding: 8pt;
}
```
### 10) Print-only adjustments (manually scoped)
```css
@media print {
.resume-preview-container .page {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
.resume-preview-container a {
text-decoration: none;
}
padding: 8pt 12pt;
}
```
## Troubleshooting
### My CSS doesn’t do anything
### My CSS doesn't do anything
- Make sure **Enable** is turned on.
- Prefer targeting `.page`, `.page-section`, and `.section-item` instead of `body`.
- Use your browser devtools to **inspect** the preview and confirm the element/class names.
### My `@media` rules affect the whole app / don’t apply
At-rules aren’t auto-scoped. Prefix selectors inside them with `.resume-preview-container` as shown above.
### My `@media` rules affect the whole app / don't apply
At-rules aren't auto-scoped. Prefix selectors inside them with `.resume-preview-container` as shown above.
+14 -8
View File
@@ -17,6 +17,13 @@ Think of it as a built-in notebook attached to each resume where you can jot dow
In the resume builder, open the **right sidebar** and select **Notes** from the available sections.
<Frame caption="Screenshot of the Notes section in the right sidebar">
<img
src="/images/guides/using-private-notes/screenshot-1.webp"
alt="Screenshot of the Notes section in the right sidebar"
/>
</Frame>
## Use cases
Private Notes are designed to help you stay organized during your job search. Here are some practical ways to use them:
@@ -35,7 +42,8 @@ Keep a record of where you've sent this particular resume:
Paste links to the original job postings so you can quickly reference them when preparing for interviews or following up.
<Tip>
Job postings often get taken down after a position is filled. Consider copying key requirements or responsibilities into your notes as a backup.
Job postings often get taken down after a position is filled. Consider copying key requirements or responsibilities
into your notes as a backup.
</Tip>
### Interview preparation
@@ -70,9 +78,9 @@ Track your follow-up schedule:
In the resume builder, click on **Notes** in the right sidebar to expand the section.
</Step>
<Step title="Write your notes">
Use the rich text editor to add your notes. You can format text with bold, italics, bullet points, and more.
</Step>
<Step title="Write your notes">
Use the rich text editor to add your notes. You can format text with bold, italics, bullet points, and more.
</Step>
<Step title="Notes save automatically">
Your notes are saved automatically as you type—there's no need to click a save button.
@@ -82,10 +90,8 @@ Track your follow-up schedule:
## Privacy guarantee
<Warning>
Private Notes are for your eyes only. They will **never** appear on:
- Your exported PDF or other file formats
- Your publicly shared resume link
- Any printed version of your resume
Private Notes are for your eyes only. They will **never** appear on: - Your exported PDF or other file formats - Your
publicly shared resume link - Any printed version of your resume
</Warning>
This makes it safe to store sensitive information like salary expectations, candid thoughts about opportunities, or personal reminders that you wouldn't want an employer to see.
+10 -5
View File
@@ -8,9 +8,10 @@ description: "Learn how to create API keys and authenticate requests to the Reac
Head over to [https://rxresu.me](https://rxresu.me) and sign in with your account credentials.
</Step>
<Step title="Navigate to API Keys settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section, click on the <Badge>API Keys</Badge> link.
</Step>
<Step title="Navigate to API Keys settings">
Once you're in the dashboard, look for the sidebar navigation on the left. Under the <Badge>Settings</Badge> section,
click on the <Badge>API Keys</Badge> link.
</Step>
<Step title="Open the API reference">
On the API Keys page, click <Badge>API Documentation</Badge> to view the API reference.
@@ -18,6 +19,7 @@ description: "Learn how to create API keys and authenticate requests to the Reac
<Tip>
You can also open it directly here: [API Reference](https://docs.rxresu.me/api-reference).
</Tip>
</Step>
<Step title="Create a new API key">
@@ -25,6 +27,7 @@ description: "Learn how to create API keys and authenticate requests to the Reac
- **Name**: A label to help you identify what you use this key for
- **Expires in**: How long the key should remain valid
</Step>
<Step title="Copy the API key (important)">
@@ -33,6 +36,7 @@ description: "Learn how to create API keys and authenticate requests to the Reac
<Warning>
For security reasons, your API key is only displayed once. If you lose it, you must create a new one.
</Warning>
</Step>
<Step title="Authenticate requests with x-api-key">
@@ -43,9 +47,10 @@ description: "Learn how to create API keys and authenticate requests to the Reac
</Info>
```bash
curl "https://rxresu.me/api/openapi/resume/list" \
curl "https://rxresu.me/api/openapi/resumes" \
-H "x-api-key: YOUR_API_KEY"
```
</Step>
<Step title="Delete an API key (optional)">
@@ -54,6 +59,6 @@ description: "Learn how to create API keys and authenticate requests to the Reac
<Warning>
Deleted API keys stop working immediately, and the action cannot be undone.
</Warning>
</Step>
</Steps>
+323
View File
@@ -0,0 +1,323 @@
---
title: "Using the MCP Server"
description: "Connect Reactive Resume to AI tools like Claude Desktop, Cursor, and Codex using the Model Context Protocol"
---
The Reactive Resume MCP server lets you manage and modify your resumes through any MCP-compatible AI tool — Claude Desktop, Cursor, Codex, and more. It connects to the Reactive Resume API and exposes tools for listing, reading, and patching resumes using 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
<Steps>
<Step title="Choose your authentication method">
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.
</Step>
<Step title="If using API key, create one">
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's only shown once.
For the full walkthrough, see [Using the API](/guides/using-the-api).
</Step>
</Steps>
## 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
{
"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
{
"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
{
"mcpServers": {
"reactive-resume": {
"command": "npx",
"args": ["mcp-remote", "https://rxresu.me/mcp", "--header", "x-api-key:your-api-key"]
}
}
}
```
<Info>Replace `your-api-key` with the API key you created in the prerequisites step.</Info>
### 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 <token>`
2. **API key fallback** via `x-api-key: <key>`
If neither is valid, the MCP endpoint responds with `401` and advertises OAuth metadata using:
- `WWW-Authenticate: Bearer resource_metadata="<instance>/.well-known/oauth-protected-resource"`
This lets OAuth-capable MCP clients 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 `/auth/oauth`.
- If the user is not signed in, `/auth/oauth` redirects to `/auth/login`, then resumes OAuth.
- If the user is signed in, `/auth/oauth` validates `client_id` and `redirect_uri`, issues 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
{
"mcpServers": {
"reactive-resume": {
"url": "https://rxresu.me/mcp"
}
}
}
```
**API key fallback:**
```json
{
"mcpServers": {
"reactive-resume": {
"url": "https://rxresu.me/mcp",
"headers": {
"x-api-key": "your-api-key"
}
}
}
}
```
### Codex (CLI / IDE extension)
Add server:
```bash
codex mcp add reactive-resume --url https://rxresu.me/mcp
```
Then log in with OAuth:
```bash
codex mcp login reactive-resume
```
API key fallback (`config.toml`):
```toml
[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
{
"url": "https://resume.example.com/mcp",
"headers": {
"x-api-key": "your-api-key"
}
}
```
## Available Tools
Tool names use a hierarchical `reactive_resume.*` prefix ([SEP-986](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/986) style) so they stay distinct when multiple MCP servers are enabled in the same client.
| Tool | Description |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `reactive_resume.list_resumes` | List all resumes with IDs, names, tags, and status. Supports filtering by tags and sorting by last updated, creation date, or name |
| `reactive_resume.get_resume` | Get the full data of a specific resume by ID |
| `reactive_resume.create_resume` | Create a new, empty resume with a name and slug. Optionally pre-fill with sample data |
| `reactive_resume.duplicate_resume` | Create a copy of an existing resume with a new name and slug |
| `reactive_resume.patch_resume` | Apply JSON Patch (RFC 6902) operations to modify a resume's data |
| `reactive_resume.delete_resume` | Permanently delete a resume and all associated files. **Irreversible** |
| `reactive_resume.lock_resume` | Lock a resume to prevent edits, patches, and deletion |
| `reactive_resume.unlock_resume` | Unlock a previously locked resume to re-enable editing |
| `reactive_resume.export_resume_pdf` | Generate a PDF from the resume and return a download URL |
| `reactive_resume.get_resume_screenshot` | Get a visual preview of the resume's first page as a WebP image URL |
| `reactive_resume.get_resume_statistics` | Get view and download statistics for a resume |
### Breaking change (tool names)
Older clients may refer to unprefixed names (`list_resumes`, `get_resume`, …). Those names are no longer used; update automations and saved prompts to the `reactive_resume.*` 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) |
| `reactive_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 `reactive_resume.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 can be used for discovery when a client cannot run a full capability scan against `/mcp/`.
## Available Prompts
Prompts are pre-built workflows that provide the AI with 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 |
| `tailor_resume` | Adapt your resume to match a specific job description with keyword optimization and ATS targeting. Requires the job description as input |
| `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 use natural language to interact with your resumes:
### 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"
### Creating & Managing
- "Create a new resume called 'Frontend Engineer 2026'"
- "Duplicate my 'Software Engineer' resume for a product manager role"
- "Lock my finalized resume so it can't be accidentally edited"
- "Delete my old draft resume"
### 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"
### Exporting
- "Export my resume as a PDF"
- "Show me a screenshot of my resume"
### 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`)
- "Tailor my resume for this job description: ..." (uses `tailor_resume`)
<Tip>
The AI will use `reactive_resume.get_resume` to inspect your current resume before making changes with
`reactive_resume.patch_resume`. This ensures the correct JSON paths are used.
</Tip>
## 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 `reactive_resume.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` |
+191
View File
@@ -0,0 +1,191 @@
---
title: "Using the Patch API"
description: "Learn how to partially update your resume using JSON Patch (RFC 6902) operations"
---
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** |
<Info>
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.
</Info>
## 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.
<Info>
If you're self-hosting, replace `https://rxresu.me` with your instance URL. The API is served under `/api/openapi`.
</Info>
## 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
{
"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
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
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": "<p>Leading the platform team.</p>"
}
}
]
}'
```
<Tip>
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.
</Tip>
### Remove an Item from a Section
Remove the second skill (index `1`) from the skills section:
```bash
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
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 proceeding. If the test fails, the entire patch is rejected. This is useful to avoid overwriting changes made by another client:
```bash
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
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. |
<Warning>
All operations in a single request are applied atomically. If any operation fails (including a `test`), none of the
operations are applied.
</Warning>
## Tips
- **Fetch first, then patch.** Use `GET /resume/{id}` to inspect the current structure before crafting your operations. This helps you target the correct paths and array indices.
- **Use `test` for safety.** When updating a value you expect to be a specific value, combine `test` + `replace` to avoid accidentally overwriting concurrent changes.
- **Batch related changes.** You can send multiple operations in a single request. They are applied in order, so later operations can depend on earlier ones.
- **The `-` index appends.** When adding items to arrays, use `-` as the index (e.g., `/sections/skills/items/-`) to append to the end.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

Some files were not shown because too many files have changed in this diff Show More