resume-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 3f16b2375723
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 70bace54357d4b57b674108f
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
AGENTS.md
# Resume

Resume is a free resume builder with no paywall at download, and a free alternative to Zety and Resume.io. It is an OpenApp in the OpenApps free apps store (https://free-apps.openapps.xyz/), owned by the OpenApps team.

## What it promises

- Free, with no limit on resumes or downloads, no trial, no watermark, no ads and no paid tier. Never add a cap, an upsell, a "made with" mark on the PDF, or tracking.
- No sign-up. Every visitor is a guest account created in the browser.
- The PDF is made in the browser, with real, selectable text. A resume is stored only when its owner shares it by link; otherwise it stays on the device. Cover letters never leave the device.
- Anyone with a resume's link can view it and download the PDF. Only someone holding its admin key can change it.
- The templates stay friendly to applicant tracking systems: real text, one column, plain headings, no images or tables. Keep heading letter-spacing small (it is drawn with the PDF's character spacing, and wide spacing makes text extractors read "SU MMA RY").
- AI assistants can do everything a person can through the public API (`functions/api.ts`), documented in `public/llms.txt`. Keep that file true whenever the API changes.

## How it is built

- `index.html` is the static landing page that search engines and AI crawlers read. Keep its copy, comparison, FAQ and JSON-LD in sync with what the app does.
- `src/` is the React app. `/` mounts the editor (`Builder`) and "Your shared resumes" (`Mine`) into the landing. `/r/<id>` is the public view; `/r/<id>/admin#k=<key>` is the owner's editor. Both hide the landing (a line in the page head sets `html.app-mode` on those paths before first paint). `ResumePage` and the Bounded client load only on those routes or when someone shares, so the landing stays light.
- `functions/lib/resume.ts` is the data model for both the app and the API: the resume as the editor holds it (eleven sections: summary, work, education, skills, projects, volunteer, awards, certificates, publications, languages, interests; the first four always show in the editor, the rest are added with "Add a section"), the settings (template, paper, optional color, section order, heading names), the conversion to and from JSON Resume (the API format and the JSON download), the plain text version, date formatting and the limits.
- `src/layout.ts` lays the resume out on pages for the three templates (Classic, Modern, Compact) and six colors: every line with its font, size and position, page breaks included (a heading stays with its first lines, an entry's title with its first bullet). The same composer lays out the cover letter, and with `reflow` lays the resume out as one long page at phone width (the "Readable" view on phones). `src/Paper.tsx` draws a layout as SVG on screen and `src/pdf.ts` draws the same layout with pdf-lib, so the preview and the PDF always match.
- The resume fonts are static Archivo (400, 600) and Newsreader (500) in `public/fonts/resume-*.ttf`, with Latin, Latin Extended and Vietnamese letters and no kerning or ligatures, so the browser, the layout and pdf-lib measure text the same way. `src/fontMetrics.json` holds their advance widths. Both come from `scripts/build-fonts.py` (sources and usage in the file). Letters outside those fonts print without their accent or as "?", and the editor says which.
- `src/store.ts` is what stays on the device (localStorage): each resume under `resume:doc:<id>` (its name, the resume, its cover letter, and the link it is shared at with a fingerprint of what the link shows), which one is open (`resume:current`), and the resumes shared from this device with their admin keys (`resume:mine`). A single draft from before (`resume:draft`, `resume:linked`) becomes the first resume.
- `src/share.ts` holds the Bounded reads and writes for shared links. Sharing again from the same device updates the same link (the button says "Update link" when the resume changed since); if the link was edited elsewhere since, it asks before replacing that version. The owner's page (`ResumePage`) follows changes made elsewhere while nothing is unsaved there, and asks the same way before a save replaces a newer version.
- `src/ui.tsx` holds the shared pieces on the kit: Dialog (a sheet on phones), ask() for confirmations, Menu (kit dropdown, arrow keys), toast with an Undo action, explain() for errors, and the resume page skeleton. Removals (an entry, a section, a resume) happen at once with Undo instead of a confirmation.
- `functions/lib/config.ts` holds the app id and the site URL used in links the API hands back.
- `policy.json` holds the data rules (the link is the permission to read; an admin key makes an owner):
  - `resumes/<id>` {data: JSON string of the whole resume, createdBy, createdAt, updatedAt}: read needs a join, update needs an owner, data is capped at 100,000 characters.
  - `resumes/<id>/joins/<user>`: anyone who knows the id can join.
  - `resumes/<id>/owners/<user>`: the creator in the creating batch, or anyone whose `resumeclaims/<id>/c/<user>` key matches `resumekeys/<id>` (the key must exist).
  - `resumekeys/<id>`: set once at creation, readable only by the public API principal, which checks the `x-owner-key` header before any owner action.
  - The keys rule mentions `@const.BOUNDED_PUBLIC_PRINCIPAL_API`, which exists only once the app exists: a brand new app first deploys with `resumekeys` read set to `"false"`.

## Working on it

```bash
npm install
npm run build        # typecheck + build to dist/
npm run preview      # the built site locally
```

Changes ship through previews and releases as your runtime instructions describe; the app is an OpenApp, so nobody deploys it directly.

Check a change by filling a full resume (with accents), switching the three templates, the colors and both paper sizes, downloading the PDF and reading its text (for example with pdftotext; headings must come out whole), writing a cover letter and downloading it, making a copy and switching between resumes, downloading JSON and importing it back, sharing it, opening the link in another browser, editing from the admin link in a third, and calling the API with curl (including a wrong owner key). Check phones at 390px wide: the bottom bar, the Readable and As printed views, and that no input is under 16px.

## Voice

Plain words, short sentences, no jargon, no em dashes. Say what happens, not how clever it is.

Change history

Quality pass: several resumes, cover letters, phone-readable shared pages
3f16b23757 · 6 hours ago
Bounded source sync
b7eb5b26b5 · 1 day ago
Bounded source sync
adae97536e · 1 day ago
Bounded source sync
3b0cf36b39 · 1 day ago