Let's get into it, what is reswork ? Reswork is a side project I've been working on it's a LaTex style resume builder, that gives you the ease of quickly editing and managing your resume.
Why am I building this?
We all know the stress and pain of trying to update our resumes. Dealing with Word documents, importing weird PDF templates from random corners of the internet, and still ending up with a resume that gets tossed out by ATS checkers is frustrating.
You might ask, why not just use an existing builder? Well, if I did, it wouldn't be my own! Jokes aside, the LaTeX resume builder I usually use has had a persistent bug for a while where long sentences won't wrap properly. They just keep going until they run off the screen, completely ignoring the margins. It’s incredibly annoying. On top of that, it lacks any built-in AI features to actually help streamline the writing process.
Tech Stack
A lot of the decisions I made were in the thoughts that I wouldn't increase the complexity of this project but alas I decided to run with the project and now I regret some of those choices ( every one has been here )
React.js + Tanstack Router: I chose this combination because it offered a lightweight, client-side routing solution without the heavy overhead or boilerplate of other frameworks. It allowed me to spin up the application quickly without worrying about complex framework configurations. In hindsight: As the project evolves, I will likely migrate to TanStack Start. Having access to Server Actions and Server-Side Rendering (SSR) would drastically improve performance and simplify data handling for certain aspects of the app.
Typescript: Well typescript is the lords language, this is my default choice for all projects cause it allows for errors that might have gone unnoticed to be caught before the code leaves our editor and it increases the overall ergonomics of building out applications.
React-pdf: I used react-pdf for building out the template documents and generating the completed pdf blob. I choose this cause it was a mature library already and it provided support for the main thing I needed ( Templates ) component-driven document rendering.
Dexie.js ( IndexeDB ): Reswork is designed to be offline-first. To store resumes directly in the browser, I chose IndexedDB as it is far better at handling more complex data than localstore. However, working with the native browser API can be very frustrating, so I used Dexie.js as a wrapper which provides a clean interface with said api.
Convex: I made use of Convex for online and cloud syncing of data, it gave me access to a pesduo realtime data store, and removed the hassle of me coding out my own data sync engine.
Better-auth: To complement Convex, I integrated Better Auth to handle my authentication removing the hassle of rolling out my own authentication in favor of a ready made and mature solution that saved me time and will continue to save me time in the future if I decide to add more authentication options.
@vercel/ai-sdl: For the AI features, I chose the Vercel AI SDK utilizing gpt-5.4 mini. It was the perfect fit for a side project, giving me access to powerful language models without costing me an arm.
Solving the PDF Generation Issue
The first major challenge I tackled was figuring out how to build the document in a way that naturally fit into the React paradigm. That’s when I came across react-pdf. It allowed me to construct PDFs directly as React components and handle the layout using a CSS-like styling system. This approach made the architecture highly modular. I hand-coded every template to ensure the underlying structure remains clean, readable, and scores as high as possible when passed through ATS checkers.
To generate the actual PDF blob, I relied on the usePDF hook, which exposes an updatePDF function. To keep the live preview feeling snappy without completely destroying the browser's performance, I didn't want to re-render the PDF on every single keystroke.
Instead, I made updatePDF fire only after the resumeData state updates and a debounce period has passed. This guarantees quick, smooth, real-time edits without choking the main thread.
Integrating AI: Help Make Your Experience Standout
One of the main reasons for building Reswork was wanting AI to help me write my resume, specifically to refine my responsibilities and highlight the actual impact I had in previous roles.
However, setting this up was much harder than I initially imagined. (Why did I choose client-side routing instead of a framework with built-in server capabilities!) Since I couldn't securely call the AI API directly from the frontend, I had to spin up a minimal Express server and integrate it with Vercel's AI SDK.
This feature also forced me to write my very first system prompt. I had to dive into prompt engineering, figuring out how to guide the model to give the best, most professional answers while using as little tokens as possible.
Speaking of tokens, I quickly realized I needed safeguards so users wouldn't burn through my API limits. I expanded the users table in my Convex database to include a tokenCount, which tracks the number of AI requests a user can make on the platform. This drastically uped the complexity of my backend, my server now needed to securely interface with Convex to fetch the user's token balance, authorize the request, and deduct tokens afterward. To keep the codebase clean and maintainable, I abstracted all of this logic into an isolated, dedicated Token Service.
Challenges I faced along the way
Oh, the errors, the bugs, and the cross-browser compatibility issues. Here are some of the issues I came across while building ( some I'm still facing );
Initially, I opted to render the live preview inside a standard iframe, relying on the browser's native PDF renderer. This created more problems than it solved, as the preview would flicker black with every single re-render. To fix this, I introduced a "buffer iframe" solution: I overlapped two iframes. The active one sat at 100% opacity, while the inactive one was hidden at 0% opacity. When resumeData updated, the inactive iframe would load the new PDF blob in the background. Once it fully loaded, the two iframes would swap opacities. It work until I realized it only worked on non-Chromium browsers. Chromium handles PDF differently than Firefox, making my swap logic useless. I had to move away from the native iframe approach entirely and replace it with a custom react-pdf renderer powered by Mozilla's pdf.js.
Another major issue I ran into was what made me switch from google/GenAi + gemini-3.5-flash to vercel/ai-sdk + gpt-5.4-mini, cause for some reason unknown to me the gemini model kept taking 30s - 2mins to respond to what seems to me a very basic prompt with minimal thinking and no tool calls, I assume it was cause I was on the free tier but still I didn't want to dedicate money to a model that wasn't reliable enough for me, so I decided to pivot to a provider that let me use multiple models incase on gave me issues I could always make use of others and I decided on the gpt-5.4-mini model which gave a response time between 2s - 3.4s.
As of right now, I still don't have a perfect fix for viewing the PDF preview on mobile devices. It is a harsh trade-off: either scale the view down so the whole page fits (which turns the text into illegible, tiny blobs), or scale the text up so it is actually readable. I opted for readability. This means mobile users currently have to scroll horizontally and vertically to view all parts of their generated resume. It is a compromise, and definitely something I plan to improve in the future.
What’s Next on the Roadmap?
Reswork is still very much a living project, and I have some exciting ideas lined up to make it even more powerful.
- More Templates: I am working on adding a wider variety of ATS-optimized templates, giving users more stylistic choices while keeping the underlying structure perfectly readable for ats parsers.
- Conversational AI Builder: I want to introduce a chat-based interface where you can just vaguely describe what you did at your last job, and the AI will translate that into punchy, impact-driven bullet points formatted perfectly for your resume.
- Custom JSON Imports: A developer-friendly feature allowing you to bring in your own resume JSON file and have it automatically converted to match Reswork's internal data structure.
- Smart Resume Parsing: Nobody likes copying and pasting their old resume into a new tool. I plan to add an upload feature where the platform analyzes your existing resume (PDF or Word), extracts the text, and automatically maps it into your Reswork profile. From there, you can update it or instantly drop it into one of the platform's templates.
Wrapping Up & Where to Find the Code
Building Reswork has been an incredible learning experience—complete with its fair share of architectural regrets, late-night debugging sessions, and rewarding breakthroughs. It has pushed me to rethink how I handle state ( I love useReducer now ), manage real-time synchronization, and integrate AI seamlessly into a user workflow.
If you want to poke around the codebase, critique my architecture, or spin it up locally, everything is open-source! You can find the repositories here:
I am actively looking for feedback and completely open to contributions. If you spot a bug I missed, have an idea for a new template, or want to tackle one of the roadmap features, feel free to open an issue or submit a pull request. And of course, if you like what I’m building, a star on GitHub goes a long way!
Thanks for reading, and happy coding!


Top comments (0)