Inspiration

This started with being on the other side of it.

I have applied to a lot of things and never heard back. Not a rejection, just silence. That is a strange thing to sit with, because you never find out whether you were read and passed over or simply never read at all.

Talking to friends, I found everyone had the same story. So I asked a family member who handles hiring at a nonprofit what actually happens to a stack of applications. She described it plainly. The team looks through the postings, finds the people they need, and does not get to the rest. Not out of laziness. The role gets filled and the work does not stop.

That is a bad outcome twice over. The applicant who spent a real evening on their application never gets read, so their result had nothing to do with merit. And the employer never learns who else was in the stack. The person who would have been perfect might have been at number forty.

The pressure is getting worse rather than better. 54% of small business leaders say AI-generated applications have made hiring harder (Robert Half, 2026), and two-thirds expect attracting talent to be difficult (NEXT Insurance, 2026). Applicants now use AI to apply in bulk, so volume goes up while relevance goes down. The businesses feeling it hardest are the ones with nobody whose job it is to read résumés.

I wanted to build the thing that reads all of them.

What it does

You describe the role in plain English. A sentence or two about what the person will actually do day to day.

APTwell turns that into a weighted scorecard: four to six criteria, each spelling out what weak, adequate and strong evidence looks like for that specific job. The weights must total exactly 100. It is yours to edit. Change the wording, change the weights, delete a criterion, write your own.

Every applicant is then scored against your criteria. Each score comes with a written justification and the exact line from the résumé it was drawn from, so you can check the reasoning instead of trusting a number. You also get the claims worth verifying before you hire, and six interview questions per candidate aimed at whatever they are least proven on.

It never rejects anyone. It ranks, it explains, and the decision stays with the person making it.

How I built it

I decided what it was before writing any code. A B2B SaaS product for businesses that hire without an HR function. That decision fixed everything downstream: the pricing, the onboarding, and the fact that it had to work for someone making one hire rather than someone running a pipeline.

Then I looked at what already exists. Every AI résumé screener I found works the same way. You pick a job category from a dropdown, or you paste a job posting, and it matches against that. Two things bothered me about it. If the posting does not spell out what actually matters, and most postings do not, you get confident rankings built on the wrong thing. You also get a match percentage with no reasoning behind it, so you cannot tell why someone ranked low or disagree when the software is wrong.

So the design became two rules. The employer writes the criteria in their own words, and the software shows its evidence. I have not found a competitor that does the second one.

The stack is React 19, TypeScript and Vite on the front end, Firebase Authentication and Firestore for accounts and data, Cloudflare Pages for hosting with Pages Functions as the API, Gemini (gemini-3.6-flash) for scorecard generation and scoring, and Stripe Checkout and Billing for the subscription.

I used Claude Code heavily, which is how a solo project got this far in two weeks. That was not hands off. I wrote the plan, chose the architecture, tested every path by hand, and spent more time reading and correcting output than generating it. Several of the bugs below are ones I found trying to break my own app, not ones the model flagged.

The piece I would point at is the shared/ directory. Every endpoint's real logic lives there, across nine modules covering auth, rate limiting, entitlement, scorecard generation, scoring and Stripe. In development a Vite middleware calls those modules. In production a Cloudflare Worker calls the same ones. One implementation and two thin runtime adapters, so development and production cannot drift apart.

Scoring is arithmetic rather than a judgement call. The model rates each criterion on its own evidence and the code does the maths:

$$ \text{score} \;=\; \frac{\sum_{i} w_i s_i}{\sum_{i} w_i} \qquad \text{where} \quad \sum_{i} w_i = 100 $$

Each per-criterion score \( s_i \) is rounded to a five-point step before it gets weighted, because the model has no business expressing the difference between 87 and 88.

Challenges I ran into

Time, ahead of everything else. I only found out this hackathon existed near the end of its submission window. My first commit was 30 July and the deadline is 17 August, which gave me 18 days out of a 90 day submission window. I found out about the competition with a fifth of it left. I decided to enter anyway rather than sit it out, and every other problem on this list was made worse by that choice. The idea, the build, the testing, the deployment, the payments and the marketing all had to fit inside those 18 days.

Entitlement could be forged from the browser console. The plan field on the user document is written by the client, so anyone could edit it in about ten seconds and give themselves Pro. Nothing that costs money can depend on a value the user controls. The server now answers "is this account Pro?" by asking Stripe about the subscription itself, and never by reading that field.

Deleting a role reset the free trial. The free allowance was counted from live documents, so deleting a role zeroed the counter and handed the user a fresh trial. That is an unlimited free plan for anyone who noticed. Usage is now counted from an append-only audit log, which Firestore rules make impossible to reduce.

The same résumé scored differently on different runs. Scoring defaulted to temperature: 0.2, so identical inputs returned 87 one minute and 91 the next. That is fatal for a product whose whole argument is that the ranking is defensible. It now runs at temperature: 0 with a fixed sampler seed.

On top of those: checkout failing, environment variables not taking effect after a deploy, Firestore permission rules rejecting valid queries, and a front end that took several passes before it looked like something you would trust with a hiring decision.

Accomplishments that I'm proud of

That I started at all. It would have been very easy to look at 18 days, decide there was not enough time, and do nothing. I decided to try and find out instead, and that turned out to be the whole difference.

Inside that window I got a live web app, a working Stripe checkout with a real Pro tier, and a free trial that does not ask for a card.

I also refused to spend all 18 days head down in the code. With that little runway I could not afford to build for a month and only then find out whether anyone wanted it, so I ran outreach in parallel with development. I was cold emailing local businesses and organisations who I thought would need this while APTwell was still half built, squeezing the sales work into the same days as the engineering because there were no spare days to put it in.

One of them came back. Rick Weldon, President and CEO of the Frederick County Chamber of Commerce, was interested enough to talk about a demo. We have not settled a date and I am still waiting to hear back. But a cold email from a student with an unfinished product reaching the head of a county business organisation told me the problem was real before the code was.

Marketing started inside the same window. The Instagram account has reached roughly 4,000 views on a post, LinkedIn posts are running in the low hundreds, and I have started posting on X.

What I do not have is a paying customer, and I am not going to dress that up. Eighteen days was enough to build the product and start putting it in front of people. It was not enough to close anyone. With the full submission window, far more of that time would have gone into conversations instead of code.

What I am proudest of in the product itself is that it refuses to make the decision. Every design pressure pushed toward "here is your best candidate." The useful thing to build was software that ranks, cites its evidence, and then stops.

What I learned

That the fastest way to learn something is to need it working by Friday.

Concretely: front-end and back-end development against a real deploy target, debugging across two runtimes, Stripe subscriptions, Firebase security rules, environment variables and secret handling, wireframing and front-end design, and running a repository properly instead of as a folder of files.

There was a harder lesson underneath all of it. Determinism matters more than accuracy for trust. A tool that is consistently a little wrong can be audited. A tool that is usually right but never the same twice cannot be defended to a candidate who asks why.

What's next for APTwell

This is not a hackathon project to me. It is my startup and I am continuing it either way. The deadline was the thing that made me start.

The feature I most want to build next is a plug-and-play connection to wherever the job is actually posted, starting with LinkedIn. Right now you bring the résumés to APTwell. Instead the employer should be able to connect the posting once and have every application flow straight in, then get the same treatment automatically: criteria drawn from how they described the role, a score against each one, the claims worth verifying, and the interview questions. The important part is that it reads the whole application rather than the résumé alone. Cover letters, screening answers and portfolio links all carry evidence, and throwing them away to look at one PDF loses most of what the candidate actually told you.

Before that, a custom domain. Then marketing hard on Instagram, LinkedIn and X, and going around campus at the University of Maryland to put it in front of real businesses and find out whether it solves the problem I think it does.

After that, letting an owner keep one scorecard across repeat hires for the same role, so the second time you hire a front desk manager you are not starting from a blank page.

Built With

Share this project:

Updates