Version: v0.15 · Effective date: 2026-10-21
This policy is pre-release (0.x). JobPuul has not launched and has no registered users, so this document is not yet claiming the stability a 1.0 would. While it is 0.x we revise it as the product takes shape and publish each revision as it is made; § 12's 14-day notice and in-app notice bind from v1.0 onward, which is the version that will be in force when the first account is created. Every revision is still dated, and every prior version is in this repository's git history at
docs/legal/privacy.md.The renumbering, so the trail below is followable. The revision published 2026-08-18 as v1.0 is this document's v0.1; the revision published 2026-08-31 as v1.1 is superseded by v0.2 and never took effect. Both are in this repository's git history under their original headings — § 12 explains how to request a specific past version.
What changed in v0.15: § 6 now says how long a session record is kept. A session that has expired is deleted by the nightly cleanup 90 days after it expired, instead of being kept until you sign out or delete your account. The last 90 days of sessions are still what we compare a new sign-in with (§ 3.1). § 3.10 now says that a few essential emails still reach you after you report one of ours as spam, and § 4 gives security alerts, not application status, as its example of transactional email: application status emails can be switched off.
What changed in v0.14: two of your rights requests now say how long we keep them, a company's owners can now enter its addresses (§ 3.3, § 6), and emails we had prepared but not yet sent now go out, each listed below.
- A copy of your data you ask for (§ 9, Access) is kept only until its download link expires, seven days after we email it to you, and asking for a new copy replaces the previous one. Downloading it does not delete it, so an interrupted download can be retried.
- A request to delete your account: the confirmation link we email works for one hour. Once it expires we delete it, either when you ask again or in the nightly cleanup, and asking again sends you a new link (§ 9, Erasure).
- A company's addresses: a company's owners can now enter its registered, billing and office addresses. An office can be placed on the map exactly, but only when an owner ticks "Show this office on the map"; otherwise its position is rounded to about 1 km (§ 3.3). Closing a company deletes its addresses (§ 6).
- Changing your email address is now something you do yourself (§ 3.1, § 9): we email a link to your current address, then one to the new address, and once the change is made we tell the old address. An address you change away from is no longer linked to your account, so if we had stopped emailing it, § 6 says what happens to that record.
- Security emails (§ 3.1): we now email you when your account is signed in to from a device it has not used in the last 90 days, when its password or ways of signing in change, when a passkey is added or removed, and when two-factor authentication is turned off. To tell a new device, we compare the sign-in with your account's sessions from those 90 days. § 6 now says how long a session record is kept.
What changed in v0.13: after you sign up, the page asking you to confirm your email address learns that address from a cookie,
jp_verify_email, kept for one hour, instead of from the page's web address, which ends up in server logs and your browser history (§ 3.11). § 3.11 also listsjp_anon, which we already set and had left out: a random identifier that ties the record of a cookie choice made while signed out to that browser.What changed in v0.12: several features arrived together, so this revision covers each of them.
- Signing in. You can sign in with Apple, Microsoft or GitHub as well as Google, where we have switched each on (§ 3.1, § 13). LinkedIn is not a sign-in option. To limit password guessing, we keep your IP address and the account page you requested for up to ten minutes after your last request (§ 3.8). Cloudflare's bot check, Turnstile, can protect sign-up, sign-in, the contact form and the illegal-content notice form; what it keeps in your browser is strictly necessary security storage, which needs no consent (§ 3.11, § 5).
- Companies with several members. Several people can now run one company (§ 3.3). Its members see each other's names, roles and when they joined, and an owner or company admin can invite a colleague by email — we keep the address they type until the invitation is used, withdrawn or expires after seven days (§ 6). If you are the only owner of a company, you hand it over or close it before you delete your account (§ 9); if your account is deleted for inactivity, § 6 says what happens to such a company.
- Locations and maps. If you use "Use my current location" and then save your profile, or an offering you provide yourself, we now keep that position, rounded to about 1 km, and show the profile or offering there rather than at the town's centre; the form says so before you save and lets you remove it. A pin you place is kept the same way. For an offering you provide yourself you can choose to show a pin's exact position, for a business address, with that address beside it if you type one, and withdraw that choice at any time (§ 3.2); we publish them under our contract with you, not on consent (§ 4). Jobs, services and people can be shown on a map. The map is drawn from tiles we host on our own Cloudflare domain, so when you open it your browser asks Cloudflare for the tiles of the area you are looking at, and that area appears in Cloudflare's access logs like any other request (§ 3.8, § 5). No one else is asked. R2 now also holds the map's tiles, which contain no personal data (§ 5, § 10).
- Applying with your profile. We do not accept CV files: applying shares your profile with the company that posted the job, as it is now and as you update it, until you withdraw the application. A company member can download it as a CV document, which we generate when they ask and do not keep (§ 3.5, § 6).
- Saved jobs. We keep the jobs you save, and when you saved them; only you can see them (§ 3.5a, § 6).
- Reports and blocks. Anyone can now tell us about content they believe is illegal, with or without an account (§ 3.13). Without an account, the name and email address you choose to give us are kept until six months after our decision, and then deleted automatically (§ 6). You can block another member, and we keep who you blocked and when; if you report a message, our moderators read it with up to two messages either side of it (§ 3.6, § 6). A suspension, its history and the statements of reasons we send are deleted together with the suspended person's account (§ 6).
- Where things run. GlitchTip, the tool that records application errors, is self-hosted on our own EU infrastructure, not on hardware at home. § 3.8 says so, and § 5 lists it under Hetzner instead of as a row of its own, without the Cloudflare Tunnel that reached that hardware. Our API reference page moved to
/api/v0/docs, so § 5 and § 8 name that address. It is still the only page that loads a script from jsDelivr. § 13 now says what our queue's jobs hold besides IDs, and when they are deleted.What changed in v0.11: § 3.2 lists the availability, spoken languages and education you can now add to your profile. On a listed profile they are public, and the people directory can be filtered by whether you are available now and by the languages you speak.
What changed in v0.10: when the city on your profile, an offering or a job posting is a place we can identify, we now also keep that place's identifier and the coordinates of its centre — the town's, never yours — so it can be found by place and, later, shown on a map (§ 3.2, § 3.3, § 3.4). "Use my current location" still keeps only the town it found. A home, billing or registered address never gets coordinates.
What changed in v0.9: you can now upload a profile photo, and a company owner a logo (§ 3.2). Both are stored in Cloudflare R2, which § 5 and § 8 now say holds them as well as the nightly backups, and § 6 says when each file is deleted.
What changed in v0.8: you can verify a company's domain by confirming any email address at it, not only the one you sign in with. § 3.3 says what we keep — the address you type — and § 6 says for how long.
What changed in v0.7: § 3.2 lists the work history and links you can now add to your profile, and says that you can keep a work-history entry off your public profile.
What changed in v0.6: we can now copy a bug report, translation error or suggestion you send us into our private issue tracker on GitHub — never with your name or email address, and only when one of our team reviews it and chooses to (§ 3.9). Nothing is copied until we switch this on. GitHub is added to § 5 and § 8, and § 6 says how long those copies stay.
What changed in v0.5: § 5 and § 8 name jsDelivr, the CDN our API reference page loads one script from. It was already doing so; this discloses it.
What changed in v0.4: the self-service export and deletion controls moved to Workspace → Privacy (
/me/privacy); the old address forwards there. What they do is unchanged.What changed in v0.3: § 3.2 declares the "use my current location" button: what your browser sends when you press it, and that we neither store nor pass it on.
What changed in v0.2: most of it removes claims about data we never held — we do not accept CV uploads, and the only thing in our object storage is the nightly database backup. Two changes are genuine retention changes, so under 1.0 they would have carried § 12's notice period: messages are now kept with the application they belong to rather than for a separate 36 months, and moderation records are declared as kept indefinitely rather than for 24 months. It also declares one new data class: the addresses we have stopped emailing — and, with it, the one case where an account is kept longer than 24 months: if the notice we owe you cannot be delivered, we hold the account rather than deleting it unwarned, until 30 months from your last activity and six months from the bounce have both passed.
Why 0.x rather than v1.1. The superseded revision numbered this v1.1 and recorded that § 12's 14-day notice "had no recipients". That was true and still the wrong shape: a 1.x number asserts a stability this document does not have, and an exception written into a policy is the kind of thing that outlives the reason for it. Numbering it honestly retires the exception instead — pre-1.0 carries no notice obligation because it has not started promising one. v1.0 is the commitment, and by then both mechanisms § 12 names exist in the product rather than as a promise (#557).
The short version
The full policy is below and it is what governs. In plain terms:
- What we hold: your account and profile, anything you post, applications you send (which share your profile with that company), messages, billing records, and security logs. Section 3 lists every field.
- Why: to run the platform you asked to use, to bill you if you buy something, to keep the place safe, and to meet Czech accounting law. Section 4 maps each purpose to its legal basis.
- We do not sell your data and we do not share it with advertisers (Section 7). We also do not buy it from brokers, scrape profiles, or make automated decisions about you that carry legal weight (Section 3.12).
- Who else sees it: the employers and clients you choose to apply or talk to, plus the processors that run our infrastructure — hosting, storage, email, payments, error tracking. All named in Section 5.
- Where it lives: the EU. The database and its nightly backups stay in EU-jurisdiction storage (Section 8).
- You can export or delete everything yourself at Workspace → Privacy, or email
privacy@jobpuul.com. Your full rights are in Section 9. - Under-16s may not use JobPuul (Section 11).
1. Who we are
JobPuul is a global professional network and jobs platform operated at jobpuul.com. We help people find jobs and contracting work, and we help employers and clients find them back. The service is global; the operating entity is registered in Czechia.
The data controller for personal data processed via jobpuul.com is Tomáš Zálešák, a sole trader (fyzická osoba podnikající) registered in the Czech Trade Register (živnostenský rejstřík), IČO 11765411, place of business Sochorova 3228/46, Žabovřesky, 616 00 Brno, Czech Republic.
How to reach us
- General contact (privacy queries):
privacy@jobpuul.com - Security contact (vulnerability reports):
security@jobpuul.com
We have not appointed a Data Protection Officer. We are not legally required to appoint one at our current scale; we will reassess as the user base grows.
2. Scope
This policy covers personal data processed when you:
- Create or use a JobPuul account.
- Build a public or private profile on JobPuul.
- Apply to jobs or contracts via JobPuul.
- Post jobs, review applications, or contact candidates as an employer or client.
- Send or receive messages, notifications, or posts on JobPuul.
- Pay for, or are paid via, JobPuul features (paid plans, promotions).
- Visit
jobpuul.comwithout an account (logs, cookies, security telemetry).
It does not cover:
- Third-party sites we link to. Their privacy notices apply when you click through.
- Personal data you choose to publish on JobPuul that you also publish elsewhere — we have no control over the other copies.
3. What data we collect
3.1 Account
- Email address (required).
- Hashed password (when you sign up with email/password) — we never store the plaintext.
- OAuth identity (Google, Apple, Microsoft or GitHub, when you sign in with one) — provider user ID, email, display name, avatar URL when you grant them.
- Email verification timestamp.
- If you change your email address: we email your current address a link to confirm the change, then the new address a link to verify it, and once the change is made we email the old address once more to say the account no longer uses it. That notice does not name the new address.
- Session records (device, IP at session start, user agent, expiry).
- Security emails about your account. When your account is signed in to, we compare that sign-in's browser, operating system and network (the first three parts of an IPv4 address, or the first three groups of an IPv6 one) with your account's sessions from the last 90 days. If none matches, we email your address to say so. We also email it when your password changes, two-factor authentication is turned off, a passkey is added or removed, or a way of signing in is added or removed. These emails cannot be switched off, because they warn you about access to your account.
- Two-factor authentication metadata when you enable it.
3.2 Profile
Anything you put on your professional profile, which can be public, semi-public, or private depending on your visibility settings.
- Display name, slug (
/u/<slug>), headline, bio. - A profile photo, if you upload one: a JPEG, PNG or WebP file of up to 2 MB. We keep the file exactly as you sent it — we do not crop, resize or re-encode it, so anything embedded in it (such as a camera's location data) stays in it; remove that before uploading if you do not want it shared. It is shown wherever your profile is, including the people directory; anyone who has its address can load it while it is your photo. We stop serving it as soon as you replace or remove it, and to anyone but you if your profile is hidden, though a browser that already loaded it may keep its own copy for up to a day.
- Country, city, preferred language for the interface.
- Where your city is a place we can identify in our list of places (from GeoNames): that place's identifier and the coordinates of its centre, so a public profile can be found by place and, where we show a map, shown on it at that precision. The same applies to the city of each service offering you publish. A city we cannot identify is kept exactly as you typed it, with no coordinates unless you give a position as below.
- Only if you press "Use my current location" and your browser asks and you allow it: your position, rounded to about 1 km, is sent to us once to find the nearest town in a list that ships with the app, and that town's name is filled into the field. We do not log the position, and no third party receives it. If you then save your profile, or an offering you provide yourself, we keep that same rounded position (about 1 km) with it, and a public profile or a published offering is placed there instead of at the town's centre. The form tells you this before you save and lets you remove the position; nothing is kept unless you save. An offering a company provides keeps only the town.
- A pin you place on a map, where the form offers one, for your profile or an offering you provide yourself: kept the same way, rounded to about 1 km.
- An exact business location, only if you choose it. For an offering you provide yourself, you can tick "Show this exact location publicly" for a pin you placed. Its exact position (to about 1 m) is then public on the offering's page, on the map and through our public API, and we keep the time you chose it. The form shows the choice back to you while it is on. Untick it at any time and we round the stored pin back to about 1 km in the same save; removing the pin, changing the town or making the offering remote ends the choice too, so a new pin starts at about 1 km. A profile, and a position from "Use my current location", are never kept more precisely than about 1 km. We publish an exact location because showing your offering where you choose is part of the service you asked for, so the legal basis is our contract with you, not consent (§ 4).
- A business address, only beside an exact pin. With the exact location on, you can also type the address it marks. It is optional, kept as you type it, and public wherever the exact pin is: on the offering's page and beside its pin on the map. Unticking the exact location, removing the pin, changing the town or making the offering remote deletes it in the same save. A profile, and an offering without an exact pin, never show one. As with the exact location, the legal basis for publishing it is our contract with you (§ 4).
- Our public API returns every position exactly as the page shows it, and nothing more precise exists to return. A position you remove, or one that no longer fits a town you change, is replaced in the same save.
- Employee / contractor status — the work you take on, or that you are not looking right now.
- Your availability, if you add it: the date from which you can start, how many hours a week, and whether you work remotely, hybrid or on-site.
- Languages you speak, each with your level.
- Education and certifications you add: the school or issuer, the qualification, the start and end month (for a certification, when it was issued and when it expires), and an optional description. We do not check these entries with the institutions you name.
- Work history you add: jobs you have held and clients you have worked for — the role or project, the organisation's name, the start and end month, and an optional description. You choose for each entry whether it appears on your public profile; an entry you keep off it is still your data, so it is included when you export your data and deleted with your account. We do not check these entries with the organisations you name.
- Links you add, such as your website, portfolio or GitHub profile.
- Verification signals (which method verified you and when — e.g., email-domain match, OAuth, manual review).
- One or more addresses (home, billing) — structured per country. These never get coordinates and are never shown on a map.
- One or more tax identifiers per country — for example CZ
IČO/DIČ, DESteuernummer/USt-IdNr., USEIN. We collect tax IDs only when needed for billing or for contractor surfaces; profiles that never use those surfaces have no tax IDs stored. - Country-shaped preferences and discriminators (e.g., CZ preferred employment form: DPP / DPČ / IČO-OSVČ). We do not store national identifiers (SSN, passport numbers, Sozialversicherungsnummer) in the country-extension JSON; structured-access national IDs are held separately, under strict access control.
On a profile you have listed publicly, your availability, languages and education are shown on its public page, and anyone can filter the people directory by whether you are available now and by a language you speak. All of it is included when you export your data and deleted with your account.
3.3 Companies you join
If you act on behalf of a company:
- Company name, slug, description, logo, website, size bucket, home country.
- Your role on that company: owner, company admin or recruiter.
- The other members of a company see your name, your role and when you joined. Its owners and company admins can change your role or remove you, within what their own role allows.
- If you invite a colleague: the address you type and the role you offer. We email it a link that works for seven days and only for an account signed in with that address, once the address is verified. The email names the company and you, so enter only the address of someone who expects it. The other owners and company admins see the invitation until it is used, withdrawn or expires.
- If you are invited: the company's members see the address the invitation went to until it is accepted, declined, withdrawn or expires. If you have an account at that address, the invitation is included when you export your data and deleted with your account.
- Company registered, billing and office addresses, and tax IDs. Only the company's owners can add, change or remove its addresses. A registered or billing address never gets coordinates, because a sole trader's is often their home. An office address gets the centre of its town, or a pin an owner places, which we round to about 1 km unless an owner ticks "Show this office on the map"; we then keep the pin's exact position. Unticking it, removing the pin or moving the office to another town rounds or removes it in the same save. Closing the company deletes its addresses.
- If you verify the company's domain by confirming a work email address at it: the address you type. We email it a one-time link that works only for your account and expires after 24 hours, and keep the address with the link until it is used or expires. Once it is used, we keep the address as the record of how the company was verified. The email names only the domain — not you and not the company — so enter only an address whose owner expects it.
A company record is corporate data, not personal data — but the fact that you are linked to it, and in what role, is personal data about you.
3.4 Job postings
If you post jobs, we store the postings themselves, including title, description, compensation range, location (with the coordinates of each town's centre, where we can identify the town), employment type, and country-specific shape (e.g., CZ DPP/DPČ, US H-1B sponsorship flag).
A job is recorded against the company that posted it. The person who posted it is identifiable through their membership of that company.
3.5 Applications
When you apply to a job:
- The fact that you applied (job ID, your user ID, submission timestamp).
- Your cover letter. We do not accept CV or résumé files: your profile is your CV. Applying shares your profile with the company that posted the job — every member of that company can see it on your application, even if your profile is not listed publicly. They see it as it is now and as you update it, until you withdraw the application; work history you keep off your profile is never shared, and your email address is not shown. A company member can download it as a CV document, which we generate when they ask and do not keep.
- Application status over time (
submitted→viewed→shortlisted/rejected/withdrawn). - Who changed the status of your application, when, and an optional note about why. We keep this history on purpose: if you are rejected and want to challenge that months later — under your GDPR rights around automated decisions, or under anti-discrimination law — we need to be able to tell you what actually happened.
3.5a Saved jobs
Jobs you save: which listing and when. Only you can see them — the company is not told, and no count is shown. They are included in your data export and deleted with your account.
3.6 Messages, posts, notifications
Where these features are available to you, we hold:
- Message bodies, sender, recipient, timestamps, read state.
- Post body, author, reactions, comments.
- Your notifications. A notification stores only a reference to the thing it is about, never a copy of it — so once that thing is deleted, the notification cannot show it either.
- A block list: who you blocked and when, kept until either account is deleted.
- If you report a message, our moderators read it with up to two messages either side of it.
3.7 Billing (Paddle)
We use Paddle as Merchant of Record. Paddle collects payment instruments (card, bank details, PayPal account, billing address) on their hosted checkout. We do not see or store payment instruments. We receive from Paddle:
- The Paddle customer ID linked to your JobPuul user.
- Subscription / one-off purchase events (start, renewal, cancellation, refund).
- Invoice metadata (invoice number, country of taxation, amount, currency).
- VAT-relevant billing country (Paddle computes; we store).
Paddle is the controller for the payment-instrument data; JobPuul is the controller for the link between your JobPuul user and Paddle's customer record, and for the events we receive.
3.8 Logs and security telemetry (Cloudflare, GlitchTip, app logs)
- Cloudflare access logs: IP address, user agent, request path, response code, country (derived from IP) for every HTTP request that hits
jobpuul.com. Cloudflare retains these per their published retention schedule; we read aggregates and security signals from them. - Map tiles: when you open a map of jobs, services or people, your browser fetches map tiles, fonts and icons from
tiles.jobpuul.com, our own tile server on Cloudflare. A tile's path names the area and zoom level it shows, so Cloudflare's access logs for that domain record which areas were looked at, with the IP address of the request, as for every other request. The area is also in the page's address; our own application logs record paths without the query string, so they do not keep it. No map provider outside Cloudflare is involved. - Sign-in and sign-up rate limits: your IP address and the account page you requested (sign-in, sign-up, password reset), so we can limit password guessing. Kept in our database for up to ten minutes after your last request, and never included in backups.
- GlitchTip error events: Sentry-compatible error reports including stack traces, the offending request URL and method, the user ID when one is available, browser / runtime info, and a coarse IP. GlitchTip is self-hosted on our own EU infrastructure (see §5).
- Application logs: stdout from our Next.js server and pg-boss workers, captured by Dokploy on the Hetzner VPS. These include request IDs, user IDs, action names — never message or cover-letter bodies, never passwords, never tax-ID values.
3.9 Feedback and support messages
When you use the contact / "report a problem" form — with or without an account:
- The name, email address, and message text you type, plus what kind of message it is (question, bug report, translation error, idea or suggestion, other).
- A keyed (non-reversible) hash of your IP address, used only to rate-limit the form against spam. We do not store the raw IP.
- Context we attach automatically so the report is actionable: the interface language you were using, the page path you were on (never the query string — it is stripped before storage, so links containing one-time tokens are not retained), your browser's user-agent string, your window size, and the build identifier of the running app. For a translation report you may also paste the exact wording that is wrong.
- Your user ID when you were signed in, so we can follow up. That link is severed automatically if you later delete your account.
We use this to answer you and to fix the reported problem (see §4). Deleting your account blanks the name, email, message text, captured context, and rate-limiting hash of the messages you sent while signed in.
When a report becomes a tracked issue. Once we have switched this on, one of our team who reviews a bug report, translation error, idea or other report and decides to work on it may copy it into our private issue tracker on GitHub (§ 5). Nothing is copied automatically. What is copied is the message text and the automatically attached context above — never your name, email address or account. Email addresses, and your name as you typed it and as it appears on your account and profile, are also removed from the text before it is copied, and a profile page's address is copied without the part that names its owner. The issue refers back to your message only by its internal number, which only we can look up. Questions are never copied. Your data export (§ 9) shows whether a message of yours was copied, and where.
3.10 Email we could not deliver to you
This applies with or without an account — we email people who only used the contact form, too.
- If an email we sent bounces, or you report one as spam, we record that address, which of the two happened, the provider's event id when the event carried one, and when we last heard about it. Nothing from the message itself.
- It is how we stop writing to a mailbox that rejects our mail, and how we honour a "stop emailing me". Section 6 says how long we keep it.
- A few essential emails, such as security alerts and the decision on a report you filed while signed in, still arrive after you report one of ours as spam. A mailbox that rejects our mail stops them too.
3.11 Cookies and similar technologies
We set only first-party cookies, and only these:
| Cookie | Purpose | Lifetime | Category |
|---|---|---|---|
| Better Auth session | Keeps you signed in | Session / until sign-out | Strictly necessary |
| Better Auth CSRF token | Anti-forgery protection on state-changing requests | Session | Strictly necessary |
NEXT_LOCALE | Remembers the UI language you chose | 1 year | Strictly necessary (a user-set preference) |
jp_consent | Records your own cookie choices, so we don't ask again | 12 months | Strictly necessary |
jp_anon | A random identifier, set the first time you make a cookie choice while not signed in, so our record of that choice can be tied to this browser rather than to you | 12 months | Strictly necessary (our record of your consent) |
jp_verify_email | The email address you just signed up with, so the "check your inbox" page can show it and resend the link | 1 hour, or until you sign in on that browser | Strictly necessary |
jp_consent deserves the explicit mention: it is the cookie that stores your answer to
the cookie banner. Storing a refusal requires a cookie, and leaving it out of a cookie
list — as this policy previously did — is a small dishonesty we would rather not commit.
Strictly-necessary cookies need no consent under ePrivacy, which is why the banner governs the categories below rather than the table above.
Cloudflare Turnstile, the bot check on sign-up, sign-in (including signing in to connect
an app), the contact form and the form for reporting illegal content, runs in a frame served
from challenges.cloudflare.com, once we have switched it on. To tell people from bots, it may
keep data in your browser for that site, not ours. We classify that storage as strictly
necessary security storage: it exists only to protect the form you are using from abuse, so
it needs no consent and the banner does not govern it. § 5 lists Cloudflare.
We use no third-party analytics, advertising trackers, or social-network beacons. The
consent banner exposes one optional category, analytics, and nothing currently writes
to it — it exists so that adding analytics is a decision you get asked about rather
than one that ships silently. If we add any, this section and the banner are updated
before the tag fires.
You can review or change your choices any time at /cookies.
Still to confirm before launch: whether Cloudflare's bot management sets a cookie of its own once it is enabled in front of the site, and how that classifies. It is not live yet.
3.12 What we do not collect
- We do not buy personal data from data brokers.
- We do not scrape third-party sites to seed profiles.
- We do not use special-category data (race, religion, health, political opinion, sexual orientation, trade-union membership) for ranking, matching, or advertising. You may choose to disclose some of these in your bio; that does not authorise us to process them as special-category data.
- We do not perform fully automated decisions with legal or similarly significant effects on you (GDPR Art. 22). Ranking and matching produce signals; humans make hiring decisions.
3.13 Reports and illegal-content notices
When you report a job, a company, a profile, an offering or a message, we keep what you send: the reason, your explanation and, for a notice of illegal content, the law you name.
- Signed in, the report is linked to your account. Deleting your account unlinks it and blanks your explanation and the law you named.
- Without an account you can report only illegal content. Your name and email address are optional; we ask for them so that we can confirm we received your notice and tell you our decision. We also keep the language you used the form in, to write to you in it. These are kept until six months after our decision — the period in which you may contest it — and then deleted automatically. While we have not decided, they are kept.
- To stop abuse of the form, we count submissions per network address in keyed, non-reversible form, as for the contact form (§ 3.9), and count the confirmations we send to each email address the same way, so that nobody can use the form to flood a mailbox. The nightly cleanup deletes each count once its period (an hour, or a day) has passed.
The report itself is a moderation record and is kept as § 6 says.
4. Legal basis per processing activity
We rely on the bases in GDPR Art. 6. For Czech-resident users, the same bases apply under Act No. 110/2019 Coll. on Personal Data Processing.
| Processing activity | Lawful basis | Notes |
|---|---|---|
| Creating and operating your account, profile, applications, messages | Contract (Art. 6(1)(b)) | The service you signed up for cannot be delivered without this data. |
| Publishing the exact location of an offering you provide yourself, and the business address beside it, when you choose to show them (§ 3.2) | Contract (Art. 6(1)(b)) | Part of listing your offering the way you set it up, not consent. Untick the choice and we round the location back to about 1 km and delete the address in the same save. |
| Publishing the exact location of your company's office, when an owner chooses to show it on the map (§ 3.3) | Contract (Art. 6(1)(b)) | Part of presenting the company the way its owners set it up, not consent. Untick the choice and we round the location back to about 1 km in the same save. |
| Sending transactional emails (verification, password reset, security alerts) | Contract (Art. 6(1)(b)) | These are not marketing; you cannot opt out of password reset and still have an account. |
| Billing and invoicing (Paddle integration) | Contract (Art. 6(1)(b)) + legal obligation (Art. 6(1)(c)) | Tax law requires us to keep invoices. |
| Keeping nightly database backups in R2 for 30 days | Legitimate interests (Art. 6(1)(f)) | Being able to restore the service, and your data with it, after a failure. Balanced against you by keeping the window short and the bucket EU-pinned. |
| Recording an address that bounced, or that reported us as spam, so we stop emailing it | Legitimate interests (Art. 6(1)(f)) | Continuing to write to a mailbox that rejects our mail damages delivery for everyone else, and continuing after a spam report ignores what you told us. Balanced against you by storing only the address, which of the two happened, the provider's event id when the event carried one, and when we last heard about it — never the message. |
| Handling a report or a notice of illegal content, and telling the person who filed it what we decided | Legal obligation (Art. 6(1)(c)) for a notice of illegal content — EU Digital Services Act Art. 16; legitimate interests (Art. 6(1)(f)) for other reports | Keeping the platform free of illegal and abusive content. A notice's contact details are optional and kept only until six months after the decision (§ 3.13). |
| Security telemetry, abuse and fraud prevention (Cloudflare logs, rate limits, GlitchTip) | Legitimate interest (Art. 6(1)(f)) | Balancing test: we need to keep the platform up and stop abuse; the data is minimal (IP, request shape) and short-retained. |
| Service improvement via aggregated, non-identifying metrics | Legitimate interest (Art. 6(1)(f)) | No third-party analytics at launch; only first-party server-side counters. |
| Cookies that are not strictly necessary | Consent (Art. 6(1)(a)) | None set today. The banner exposes one optional category (analytics) that nothing currently writes to — see § 3.11. |
| Marketing emails (product news, new-feature announcements) | Consent (Art. 6(1)(a)) | Opt-in only. Unsubscribe in every email. |
| Verification signals, including proof from a manual review | Legitimate interest (Art. 6(1)(f)) | Anti-spam: an unverified account is cheap to create and expensive to trust. Proof is stored as identifiers and references, never raw documents committed to the database. We do not currently accept uploaded proof documents. |
| Responding to law-enforcement requests | Legal obligation (Art. 6(1)(c)) | Only when the request is binding and properly served. |
5. Third-party processors
We disclose every processor that handles personal data on our behalf. Each of these has, or will have, a signed Data Processing Agreement (DPA) under GDPR Art. 28 unless explicitly noted.
| Processor | Purpose | Region | Contract | Privacy policy |
|---|---|---|---|---|
| Resend | Transactional email (signup verification, password reset, application status notifications) | United States | Standard DPA + EU Standard Contractual Clauses for transfers outside the EEA | https://resend.com/legal/privacy-policy |
| Paddle | Merchant of Record for paid features — checkout, billing, invoicing, tax remittance | United Kingdom (Paddle.com Market Ltd.) and Ireland (Paddle.com Inc. EU entity) | Paddle MoR contract (Paddle is the seller; we are the supplier) + DPA where Paddle processes data on our behalf | https://www.paddle.com/legal/privacy |
| Cloudflare | CDN, DNS, WAF, R2 object storage (nightly database backups; profile photos and company logos; map tiles), Workers (serving the map tiles at tiles.jobpuul.com); Turnstile, the bot check on sign-up, sign-in, the contact form and the illegal-content notice form | Global edge; EU customers' traffic served from EU PoPs where available; R2 buckets configured to EU jurisdiction | Cloudflare DPA + SCCs | https://www.cloudflare.com/privacypolicy/ |
| Hetzner Online GmbH | Primary hosting (VPS running the Next.js app, pg-boss workers, PostgreSQL); application error tracking with GlitchTip, self-hosted on our own EU infrastructure | Germany (data centres in Falkenstein / Nuremberg) | Hetzner DPA (Auftragsverarbeitungsvertrag) | https://www.hetzner.com/legal/privacy-policy |
| Cloudflare Email Routing or Seznam.cz (Email Profi) | Inbound mail for @jobpuul.com (privacy@, security@, hello@) | Global (Cloudflare) / Czechia (Seznam) | Same DPA as Cloudflare above; Seznam's own processor terms apply when used | See processor sites |
| GitHub (Microsoft) | Our private issue tracker — a bug report or suggestion our team chooses to work on is copied there, without your name or email address (§ 3.9) | United States | GitHub's Data Protection Agreement + EU Standard Contractual Clauses (their coverage of our plan to be confirmed before publish) | https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement |
| jsDelivr (Volentio JSD Limited) | Serves the script that renders our API reference page, /api/v0/docs — no other page | United Kingdom (company); files served worldwide through Cloudflare, Fastly and Gcore | No contract — jsDelivr receives the request under its own privacy policy, as controller of its request logs | https://www.jsdelivr.com/terms/privacy-policy |
Notes:
- Hetzner is the primary location of personal data. PostgreSQL (Better Auth tables, profiles, applications, messages, etc.) runs on a Hetzner VPS in Germany. It is dumped nightly to EU-jurisdiction Cloudflare R2, and each night's run deletes dumps older than the configured window, 30 days by default.
- Cloudflare R2 buckets are pinned to EU jurisdiction (
eulocation hint) so nothing we store there leaves the EEA at rest. Today that is nightly database backups, the profile photos and company logos members upload, and the map tiles, which contain no personal data. Cloudflare's edge may temporarily transit data through non-EU PoPs in flight; the DPA + SCCs cover this. - Resend is in the United States. Transfers of transactional-email payloads to Resend rely on SCCs and the EU–US Data Privacy Framework (Resend's parent is DPF-certified at the time of writing — to be re-verified before publish).
- GitHub is in the United States. It receives only reports our team chose to track, stripped of the reporter's name and email address. Transfers rely on SCCs and the EU–US Data Privacy Framework (GitHub's parent, Microsoft, is DPF-certified at the time of writing — to be re-verified before publish).
- Paddle is in the United Kingdom and Ireland. Transfers to Paddle UK rely on the UK adequacy decision (Commission Implementing Decision (EU) 2021/1772). Paddle's Irish entity handles EU customers directly.
- jsDelivr sees only visitors to
/api/v0/docs. Opening that page makes your browser fetch one script fromcdn.jsdelivr.net, so jsDelivr receives your IP address, browser details, the referring domain and the file requested. Nothing else on JobPuul loads from it, and our Content-Security-Policy stops that page from contacting any other third party. - GlitchTip adds no processor of its own. We run the application ourselves; the servers under it are Hetzner's, covered by the Hetzner DPA above.
We will publish a notification on this page before adding a new processor that processes personal data.
6. How long we keep your data (retention)
The defaults below apply unless a longer period is required by law — for example the invoice-keeping obligations under Czech accounting law — or you ask us to keep something longer. There is no reactivation window: account deletion is immediate and irreversible.
Automation status. Notifications, applications, unused domain-verification links, expired company invitations, the contact details of a notice filed without an account, account-deletion confirmation links that have expired, copies of your data whose download link has expired, sessions 90 days after they expired, and inactive accounts are erased by a nightly job, without you asking. Everything else is erased when you act — deleting your account erases it in one transaction — or is controlled by a third party, as the table says. Two rows are neither: billing events and consent records are insert-only, so their long periods are a commitment rather than something a job enforces, and we will delete on request where the law allows. You can always email
privacy@jobpuul.com; Article 17 applies regardless of what any job does.
| Data class | Default retention | Erasure trigger |
|---|---|---|
| Your account and profile, while it is active | For as long as the account exists | Account deletion request, or our closure for ToS violation |
| Profile photo | Until you replace or remove it, or your account is deleted | The file is deleted from storage as soon as the change or the deletion completes. A photo you started uploading that never finished is deleted automatically within two days. A company's logo is deleted the same way when an owner replaces or removes it |
| Account record for an inactive user | 24 months from your last activity — longer if we cannot reach you | We email you at 21 months, and never delete an account until that warning has stood for three months. Signing in normally is all it takes: the email asks you to sign in and never asks you to confirm anything, so it carries no confirmation link and no token — if you receive one that does, it is not from us. If that email cannot be delivered — your mailbox rejected it — we do not delete you on schedule, because the notice is a promise and it was not kept. We hold the account, and delete it once both of these have passed: 30 months from your last activity, and six months from the day we learned the address was dead. Whichever is later; if your mailbox dies late, that is later than 30 months. Signing in stops it — it moves your last-activity date and puts you back on the ordinary schedule. If you are the only owner of a company, the email names it. A company nobody else is a member of is closed together with your account. One that has other members keeps your account from being deleted on schedule: we tell those members, and our team hands the company over or closes it before the account goes |
| Soft-deleted users | We do not soft-delete. Account deletion is a hard delete with cascades. Where an audit entry has to survive, the actor link is SET NULL and free-text fields are scrubbed in the same transaction | Account deletion request |
| CVs / résumés | We do not accept CV uploads. A CV is generated from your profile when you or a company you applied to downloads it, and is never stored. | n/a — we hold none |
| Applications, including their status history | 24 months after the last activity in the thread — a status change or a message, whichever is later | User account deletion (cascades), or the 24-month timer |
| Messages on an application | Kept as long as the application they belong to, and deleted with it | The applications row above, or user account deletion |
| Enquiries — about a service offering, or to a company directly — and their messages | Kept until a party deletes their account — we have no timed deletion for these yet | Either party's account deletion (cascades) |
| Saved jobs | Until you remove them or delete your account | Removing a saved job, or user account deletion |
| Session records (§ 3.1): the browser, operating system and IP address a sign-in came from, and when it expires | Until it is signed out, or your account is deleted. A session that has simply expired is kept for 90 days after it expires, and the last 90 days of sessions are what we compare a new sign-in with (§ 3.1) | Deleted by the nightly cleanup 90 days after it expired. Signing out, or signing a device out under Workspace → Security, deletes that session; changing your password deletes your other sessions, and resetting it deletes them all; user account deletion deletes them all |
| Blocks | Until you lift it or either account is deleted | Deleted with either account |
| Notifications | 12 months | Automated cleanup |
| A copy of your data you asked for (§ 9, Access and Portability) | Until its download link expires, seven days after the copy is ready and we email you the link. Downloading it does not delete it, so you can download it again until then. Asking for a new copy replaces the previous one as soon as the new one is ready | Deleted by the nightly cleanup once the link has expired, or when your next copy is ready; deleted with your account |
| A request to delete your account that you have not confirmed (§ 9, Erasure): when you asked, and the confirmation link we emailed | Until the link expires, one hour after we send it | Deleted by the nightly cleanup once the link has expired, or as soon as you ask again; deleted with your account |
| An invitation to join a company (§ 3.3): the address it was sent to and the role offered | Until it is accepted, declined or withdrawn, the company closes, or it expires after seven days — whichever comes first | An expired invitation is deleted by the nightly cleanup. Deleting the invited address's account deletes the invitations to it; deleting the inviter's account keeps the invitation with the company and removes the link to the inviter |
| A work email address you entered to verify a company's domain (§ 3.3) | While its link is unused: until the link expires after 24 hours, you ask for another, or the company's domain changes — whichever comes first. Once the link is used, the address is kept with the verification record for as long as your account exists | An expired link is deleted by the nightly cleanup; everything else by user account deletion (cascades) |
| A company's registered, billing and office addresses, and an office's pin (§ 3.3) | While the company is open | Deleted when an owner removes one, and all of them when the company is closed — by an owner, or with its sole owner's account by the inactivity cleanup |
| Addresses we have stopped emailing — because your mailbox rejected our mail, or because you reported us as spam | For as long as the account exists. If there is no account at that address — you only used the contact form, you changed your account's address away from it, or your account was deleted before the event reached us — we have no timed deletion for it yet | Deleted with your account. We could argue for keeping it — it is how we honour a "stop emailing me" — but that would hold your address indefinitely after you asked to be forgotten, so we do not. Without an account there is nothing to delete it with; email privacy@jobpuul.com and we will remove it |
| Billing data (Paddle events, invoices) | 10 years | Czech accounting law (Act No. 563/1991 Coll., §31); we are not permitted to delete invoices earlier |
| Records of who changed what, and when — an application's status history, abuse reports you filed | Kept with the thing they describe: an application's history goes when the application does | Cannot be deleted on request, because that defeats their purpose. Instead, deleting your account pseudonymises them: the actor link is set to NULL and your free-text notes are scrubbed, in the same transaction as the deletion |
| The name, email address and language of someone who reported illegal content without an account (§ 3.13) | Until six months after our decision on the notice; kept while it is undecided | Deleted by the nightly cleanup. The notice itself stays, as a moderation record |
| Moderation and suspension records (an admin hiding a listing, suspending an account) | Kept until the account of the person they concern is deleted — we have no timed deletion for these | Deleted together with the suspended person's account: the suspension, its history, and every statement of reasons we sent about a measure. A report, and what our team did about it, is kept as the row on records of who changed what says. The admin's link is set to NULL if that admin's own account is deleted |
| Consent records | Kept for their evidential life | Not deleted or pseudonymised with your account, and that is the point: the record exists to prove that you consented, and would prove nothing with your identity removed |
| Reports copied to our issue tracker — message text and attached context, never your name or email (§ 3.9) | Kept as long as the issue is — we have no timed deletion for these | Not deleted with your account. Deleting your account blanks our copy of the message, and after that nothing links the issue to you. If you wrote something identifying into the message itself, email privacy@jobpuul.com and we will remove it from the issue |
| Cloudflare access logs | Per Cloudflare's published retention | n/a — controlled by Cloudflare |
| GlitchTip error events | 90 days | Automatic GlitchTip cleanup; we keep no warm archive |
| Email-sending logs at Resend | Per Resend's published retention (currently ~30 days) | n/a — controlled by Resend |
| Cookies | Per-cookie maximum age, set at issue time; session cookies cleared on logout | Logout, browser session end, or expiry |
7. Sharing your data
We share personal data only with:
- The processors listed in §5, for the purposes listed.
- Other JobPuul users as the product requires — for example, a job poster sees the application you submitted to their job; a profile marked "public" is visible to anyone (logged in or not, depending on your settings).
- Law-enforcement, regulators, courts when we receive a binding, properly served request. We log every such request internally and tell you about it unless legally prohibited.
- A successor entity in the unlikely event of a merger, acquisition, or asset sale. You will be notified in advance and given a chance to delete your account before the transfer completes.
We do not sell personal data. We do not share personal data with advertisers.
8. International transfers
Most data stays in the EU/EEA (Hetzner DE, Cloudflare R2 EU jurisdiction). Some flows leave the EEA:
- Resend (United States) for transactional email delivery. Safeguard: EU Standard Contractual Clauses + EU–US Data Privacy Framework certification (to be re-verified at publish).
- Paddle (United Kingdom) for payments. Safeguard: UK adequacy decision.
- GitHub (United States) for the issue tracker, and only for reports our team chose to track. Safeguard: EU Standard Contractual Clauses + EU–US Data Privacy Framework certification (to be re-verified at publish).
- Cloudflare edge (global) for CDN delivery. Safeguard: Cloudflare DPA + SCCs; R2 storage pinned to EU jurisdiction.
- jsDelivr (United Kingdom, global CDN edges) when you open
/api/v0/docs. Safeguard: the UK adequacy decision for jsDelivr itself; its CDN providers' edges are global.
You can request the relevant transfer-safeguard documentation by emailing privacy@jobpuul.com.
9. Your rights (GDPR Chapter 3)
If you are in the EU/EEA, the UK, or any jurisdiction that mirrors GDPR (Switzerland, parts of California, Brazil's LGPD, etc.), you have the rights below. We extend the same rights to all users globally as a matter of policy — Art. 3(2) extraterritoriality applies anyway when we offer the service to EU residents.
- Access (Art. 15) — a copy of the personal data we hold about you. Self-service from Workspace → Privacy (
/me/privacy): request an export and we email you a secure download link to a structured JSON archive of your data across every table. The link works for seven days; once it expires we delete the archive (§ 6). - Rectification (Art. 16) — correct anything wrong. Most fields are user-editable from the account settings, your email address included (Workspace → Email); for the rest, email
privacy@jobpuul.com. - Erasure / "right to be forgotten" (Art. 17) — delete your account, self-service from Workspace → Privacy. We email a confirmation link that works for one hour (two-step, to prevent accidental loss); confirming performs a hard delete with cascades. If you are the only owner of a company, you first make another member its owner or close it — both one step from the same page — so that nobody is left running a company with no owner. Closing a company closes its jobs and hides its page; the people who applied keep their applications. Rows we must keep for legal reasons (invoices, audit logs) are retained but pseudonymised — the actor link is
SET NULLand free-text scrubbed in the same transaction. - Restriction of processing (Art. 18) — pause processing while a dispute is open.
- Portability (Art. 20) — receive your data in a machine-readable format. Same export as Access; the file is JSON (with attached files as the original binary).
- Object (Art. 21) — to processing based on legitimate interest (§4). We will stop unless we can show a compelling overriding ground.
- Not be subject to automated decisions with legal effects (Art. 22) — we do not perform such decisions on JobPuul.
- Withdraw consent (Art. 7(3)) — for any processing based on consent, at any time, without affecting the lawfulness of prior processing.
- Complain to a supervisory authority — for users in Czechia, this is Úřad pro ochranu osobních údajů (
uoou.gov.cz). Users in other EU/EEA countries can complain to their local DPA; UK users to the ICO.
9.1 How to make a request (DSAR procedure)
- Email
privacy@jobpuul.comfrom the email address associated with your JobPuul account, stating which right(s) you are exercising. If you cannot use that email address (e.g., it is no longer accessible), include enough information for us to identify your account — but expect us to ask for proof of identity to prevent account takeover. - We acknowledge receipt within 3 business days.
- We respond substantively within 30 calendar days of receipt. If the request is complex or we receive a high volume of requests, we may extend by up to 60 days under Art. 12(3), and we tell you why within the original 30.
- Access and portability requests are self-service from Workspace → Privacy — you get an emailed download link to your JSON archive. (Or email us and we run the same export for you.)
- Erasure is self-service from Workspace → Privacy (two-step email confirmation); requests are otherwise confirmed in writing once the deletion has executed (typically the same day; up to 30 days when the deletion fans out across processors).
- Requests are free of charge unless they are manifestly unfounded or excessive (Art. 12(5)), in which case we may charge a reasonable fee or decline — and we explain why.
10. Security
We treat security as a precondition for the rest of the privacy promises, not as a separate concern. In broad terms:
- TLS everywhere (Cloudflare-terminated; HSTS + HTTPS-only cookies).
- Passwords hashed with Better Auth's default (argon2-class); never logged.
- R2 buckets are private. The nightly database dump, profile photos and company logos are uploaded and read by the server with credentials that are never sent to a browser. The map tiles sit in a bucket of their own that holds nothing else, read only by our tile server.
- Database access restricted to the application and a short list of admins.
- Application errors captured in GlitchTip (self-hosted) with PII scrubbing at the SDK boundary.
- Vulnerability reports to
security@jobpuul.com. We acknowledge within 3 business days. - Breach notification: if a breach is likely to result in a risk to your rights and freedoms, we notify the relevant supervisory authority within 72 hours of becoming aware (Art. 33) and inform affected users without undue delay (Art. 34) when the risk is high.
11. Children
JobPuul is not directed at children. You must be at least 16 years old (the GDPR default for digital-services consent) to use the service. We do not knowingly collect personal data from anyone under 16. If we learn we have, we delete the account.
12. Changes to this policy
We update this policy when we add a processor, change a retention period, add a new processing activity, or otherwise materially affect what we do with personal data.
- Every published version has an effective date at the top.
- We keep prior versions in this repository's git history; the file path is
docs/legal/privacy.md. You can request a specific past version by emailingprivacy@jobpuul.com. - While this policy is pre-release (0.x) — JobPuul has not launched and has no registered users — we revise it as the product takes shape and publish each revision as it is made, with its own date. There is nobody to notify and nobody relying on a prior version, so the notice period below does not yet apply.
- From v1.0 onward, for changes that affect you materially (new processor, new processing activity, expanded data collection, changed retention), we notify registered users by email to the address on the account at least 14 days before the new version becomes effective, and we show an in-app notice on first login after the change. We keep a record, against your account, of which version you were notified of and which you have seen.
- For typo fixes, clarifications, or link updates, we update silently and bump the "Last updated" date.
13. Glossary and references
- Better Auth — the authentication layer that holds your login details, sessions and any linked Google, Apple, Microsoft or GitHub identity.
- pg-boss — our queue. Owns the
pgbossschema. Job payloads are versioned. An email to your account holds IDs, the name on your account for the greeting and, for a link email (verification, password reset, change of email), the address the link is for — or, when we tell your previous address that it was changed, that address. Everything else is read from the database when the job runs. An email to an address with no account behind it — the contact form's reply and its copy to us, a notice filed without an account, a company invitation, a work address being verified — holds that address and what the email says, such as the message you sent us. A job is deleted seven days after it completes or finally fails; one that never runs is deleted 14 days after it was due. - R2 — Cloudflare's object store. Used for nightly database backups, profile photos and company logos, and the map's tiles. EU-jurisdiction buckets.
- DPA — Data Processing Agreement under GDPR Art. 28.
- DSAR — Data Subject Access Request.
- DPF — EU–US Data Privacy Framework.
- SCC — Standard Contractual Clauses for international transfers.
- GDPR — Regulation (EU) 2016/679.
- Act No. 110/2019 Coll. — the Czech law implementing GDPR alongside the EU regulation.