Last updated 2026-09-25
Privacy policy
This policy explains what personal data vitrinka handles, why, for how long, and what you can do about it. It is written against the actual data model, not a template.
1Who is responsible
vitrinka is operated by LEFTEQ s.r.o., a company registered in the Czech Republic. We are the controller for the account and business data described in section 4.
- Registered name
- LEFTEQ s.r.o.
- Registered address
- Herálecká IV 1583/4, Krč, 140 00 Praha 4, Czech Republic
- Company ID (IČO)
- 21624062
- VAT ID (DIČ)
- CZ21624062
- Privacy contact
- privacy@vitrinka.ai
- Data protection officer
- We have not appointed one — our core activities do not involve large-scale, systematic monitoring of data subjects, and the journey recorder processes what our customers record on their instructions, as their processor. We revisit this assessment when the product changes.
The service is provided from the European Union. GDPR (Regulation 2016/679) and the Czech Act No. 110/2019 Coll. apply.
2The short version
- You bring content into a workspace. That workspace is a separate database file, a separate object-storage prefix and its own encryption key. It is yours.
- We handle the personal data we need to run accounts, billing and support.
- Recorded browser sessions can capture anything that was on screen in the app you were testing. Read section 6 before you use the recorder.
- AI features run either on a provider key you supply — content then goes to the provider you chose, under their terms — or on eve, our own AI service, paid from your organisation's prepaid AI balance. Section 8 explains both paths.
- You can connect AI assistants such as Claude or ChatGPT to your organisation's workspaces. What a connected app can reach, and how you cut it off, is section 7.
3What we never do
These are commitments we can make honestly because of how the system is built:
- We do not train AI models on your content
- There is no training pipeline in vitrinka, and eve, our own AI service, does not train on customer content either. Content leaves the service only when you ask for an AI action — to the provider you connected, or through eve to the model providers behind it.
- We do not sell your data
- And we do not share it with advertisers or data brokers.
- We do not run advertising or cross-site tracking
- The public marketing pages set no cookies and load no analytics or third-party embeds at all. Inside the product, analytics and error tracking are self-hosted on our own infrastructure, cookieless, with no persistent cross-session identifier.
- We never store your password
- Passwords are stored by us as argon2id hashes on our own infrastructure — never in plaintext. We store passkey public credentials, not secrets.
- We never store your AI provider key in plaintext
- It is encrypted with AES-256-GCM under a master key held only by the server process, bound to your organisation. The database layer never sees the plaintext.
- API tokens, session cookies, connector tokens and share-link secrets are stored only as hashes
- We cannot show you a token again; we can only revoke it and mint a new one.
We also do no automated decision-making with legal or similarly significant effect. Nothing in vitrinka profiles you or decides anything about you.
4Two roles: controller and processor
We are the controller for the data we need to run vitrinka as a business: your account, your organisation, billing, support and security.
We are your processor for whatever you put into a workspace: board content, uploads, artifacts, project data and recorded sessions. You decide what goes in and why. If that content contains other people's personal data — your colleagues, your customers, whoever appeared in a recorded session — you are the controller of it and we act on your instructions.
The split has teeth: our data processing agreement, published at /legal/dpa, applies to the processor half and forms part of the contract with every workspace-owning organisation.
Data we receive about you from someone else. If a colleague invites you, we receive your email address from them to deliver the invitation, and we tell you in that email. If you sign in with GitHub or your organisation's SSO, we receive your name, email and identity subject from that provider, because you chose to sign in through it.
5What we store, and where
Control plane (control.db) — we are the controller.
| Data | Where | Notes |
|---|---|---|
| Email, display name, external identity subject (local, GitHub or your SSO provider), account creation and last-seen timestamps, platform-admin flag | users | The identity record. Passwords are not here. |
| Password hashes | local_credentials | argon2id only — the plaintext is never stored. Accounts signing in via passkey, GitHub or SSO have no row here. |
| Organisation and workspace names, slugs, plan, suspension flag | orgs, workspaces | |
| Who belongs to what, and with which role | org_members, memberships | |
| Browser sessions | sessions | SHA-256 of the cookie value, user id, created, last-seen and expiry timestamps. |
| Passkeys | webauthn_credentials | Public credential material and a name you choose. No biometrics ever reach us. |
| API tokens | tokens | SHA-256 of the secret, kind, workspace, role, name, agent display name, created and last-used timestamps. Connector access tokens live here too, with their scope and grant. |
| Connected-app authorisations | oauth_clients, oauth_codes, oauth_refresh, oauth_grants | Client metadata, short-lived codes and rotating refresh tokens (hashes only), and the grant record: which app, which user, which organisation and home workspace, which scope. See section 7. |
| Security audit trail | audit_log | Consent, revocation and denied-access events with timestamp, actor, IP address and browser user agent. Append-only by design. |
| Share links | share_links | Hash of the secret, an encrypted copy so you can re-copy the URL, board slug, mode, expiry, argon2id hash of the passphrase. |
| Invitations | invites | Invited email address, roles granted, who invited them, expiry and acceptance state. |
| Waitlist entries | waitlist | Email address and approval state. |
| Notification preferences and delivery targets | notif_prefs, push_subscriptions, tg_link_codes | Web-push endpoints per device; a Telegram chat id only if you link one. |
| Delivered notifications | notifications | Title, short body, link, read state. |
| UI preferences | user_preferences | Theme, layout and similar. |
| Billing identifiers | orgs.stripe_customer_id, orgs.stripe_subscription_id | Pointers into Stripe. No card data. |
| AI provider hookup and credit balance | org_ai, credit ledger | Provider name, model, base URL, the encrypted key if you brought one, and a per-organisation credit balance and usage ledger when you use eve. |
| GitHub connection | github_installations | Installation id and account login, when you connect the GitHub app. |
- Workspace content (one SQLite file per workspace, plus object storage) — we are the processor. Boards and their cards: text, documents, diagrams, UI mockups, charts, checklists, questions, chat cards, links.
- Annotations, threads, replies and work items, with the actor name attached to each write.
- Screenshot sets and their manifests: file names, routes, surfaces, notes, branch, commit, pull request and issue references.
- Uploaded files: images, PDFs, other documents, and user-supplied HTML artifacts.
- Recorded sessions:
sessionsandsession_events(see section 6). - Recorded meetings you choose to upload: the audio, its transcript (produced on our own servers when your organisation turns on server transcription) and the notes Eve writes from it.
- Tasks, sprints and milestones, including reporter and assignee names your workspace records on them.
- Project indexes pushed from your repository: file paths, route names, command palette entries.
- Board snapshots, card versions, trash and operation history.
- Technical data. Server logs: request paths, status codes, timing, IP address, user agent. Error reports go to a Sentry instance and product analytics to an umami instance — both self-hosted on our own infrastructure, so no third party receives them. The analytics are cookieless and keep no persistent identifier across sessions.
Blobs — screenshots, uploads, PDFs, artifact files, DOM-recording chunks, region snapshots, thumbnails and rendered stills — live in Hetzner Object Storage under a key prefix belonging to your workspace, encrypted with your workspace's own key before they leave our server, with a read-through cache (also ciphertext) on the server's local disk.
6Recorded sessions — read this one
The journey recorder captures a manual testing run in an application you choose. It is the most privacy-sensitive part of the product.
What a recording contains. Each session is a stream of events (session_events), each with a client timestamp, a browser tab id, the tab's host, a kind and a payload:
- rrweb
- a DOM recording of the page, which is what makes pixel-accurate replay possible;
- shot
- screenshots;
- nav and click
- navigation and interaction;
- request
- network calls, including headers and bodies;
- console
- console output;
- note
- notes you type.
- The session row also carries a title, the project and environment, the actor, and a metadata bag with user agent, app version and commit.
- Whatever was on screen or in a request can be in the recording. Customer names, email addresses, order details, tokens in URLs — anything the redaction described next does not catch.
- Redaction is on by default. The recorder scrubs authentication-bearing headers (
Authorization,Cookie,Set-Cookie, API-key and CSRF headers and the like) and known-sensitive body fields (passwords, tokens, secrets, card numbers and similar) from recorded network traffic before it leaves the browser, and masks form inputs in the DOM recording. Your workspace can extend the policy. The same policy is enforced again on our servers when events arrive, so an outdated or modified recorder cannot bypass it. Turning redaction off entirely ("full fidelity") is not available on the hosted service — it exists only for self-hosted deployments whose operator explicitly enables it. - Redaction reduces, it does not eliminate. Key-wise scrubbing covers JSON, form-encoded and well-formed multipart bodies; other content types get pattern-based scrubbing only, and anything visible on screen that is not a form input still appears in screenshots and the DOM recording unless your workspace masks all text. Treat recordings as containing whatever was on screen.
- Roles. You are the controller for what your recording captured. We are your processor. We do not inspect recordings, and we do not use them for anything except storing, replaying and projecting them onto your boards at your request.
- Your obligations. Record only applications you are entitled to record. Have a lawful basis for the personal data a recording captures, and inform the people it concerns where the law requires it. Prefer test data.
Lifecycle. An idle recording is closed automatically after 24 hours. Deleting a session first soft-deletes it — hidden but restorable for a grace window of 30 days — and after the grace window a sweeper permanently destroys it: the event rows, the screenshots and replay streams in storage, the derived boards and search entries. Your workspace can also set a maximum session age; finished recordings older than it enter the same deletion pipeline automatically. See section 12.
7Connected apps: Claude, ChatGPT and other MCP clients
You can connect an AI assistant — Claude, ChatGPT, Codex, or any client that speaks the Model Context Protocol — to your vitrinka workspaces. The connection is an OAuth authorisation: the app never sees your password, and you approve exactly what it gets on a consent screen that names the app, its origin, the home workspace and the permission level, and says the connection reaches every workspace of that organisation you are a member of.
What data a connected app can reach. A grant covers the workspaces of one organisation that you are a member of; the workspace you pick at consent is where a call lands when it names none. Within them, the app can read what you could read: boards and cards, screenshot sets and artifacts, annotations and threads, recorded-session metadata and summaries, project memory, templates, components, tags, and tasks, sprints and milestones. With write permission it can also create and edit those things, acting under your name and never with more power than your own role (capped at member — a connected app is never an admin).
What we receive from the app — and what we do not. We receive only the tool calls the assistant makes against your workspace: the operation and its parameters. We do not receive, request or store your conversation with the assistant, and the connector has no way to ask for chat history. In the other direction, whatever a tool call returns to the assistant becomes part of your conversation with that provider — from that moment Anthropic's, OpenAI's or your client vendor's own privacy policy governs it.
- Purpose
- Let an assistant you chose work your boards for you — and nothing else. Connector data is not used for analytics, advertising or training.
- Permissions (scopes)
- Exactly two levels: read (see boards, sets and artifacts) and read + write (also publish and edit as you). Write implies read; the level is shown on the consent screen and enforced on every single call — a read-only connection attempting a write is refused at three independent layers.
- One app, one user, one organisation
- Every grant is bound to the app that requested it and the user who approved it, and reaches the workspaces of that user's organisation, never another organisation's. Viewers cannot connect apps at all; if your membership ends or drops below member, the grant is revoked automatically.
- Token handling
- Authorisation codes live 5 minutes. Access tokens live 1 hour and are deleted at expiry. Refresh tokens live at most 180 days, rotate on every use, and a rotated token presented twice is treated as theft: the whole connection is revoked on the spot. All of them are stored as SHA-256 hashes — never as plaintext. App registrations unused for 30 days are deleted.
- Your controls
- Settings → Connected apps lists every connection you have made — app, origin, home workspace, permission level, when it was created and last used — and revokes any of them with one click. Workspace admins have the same list and the same revoke for every connection into their workspace. Revocation immediately invalidates the app's tokens; the next call fails.
- Audit trail
- Every consent, every revocation (yours, an admin's, or an automatic security revocation) and every denied attempt is recorded with timestamp, who acted, the IP address and browser it came from, and the app and scope concerned. The trail is append-only — nobody, including us, can quietly edit it — and it is kept for the life of the organisation as a security record.
The same facts, in directory language: categories of data — workspace content as listed above, plus the grant and token records; purposes — executing the tool calls you asked your assistant to make; recipients — the AI provider whose assistant you connected (Anthropic, OpenAI, or the vendor of your MCP client); retention — tokens as stated here, grant records until revoked, audit records for the life of the organisation; user controls — the consent screen before, the Connected-apps pages and automatic security revocations after.
8AI processing
vitrinka's AI features run on one of two paths, and your organisation decides which:
- Your own provider key
- Your organisation connects OpenRouter, OpenAI, Anthropic, any OpenAI-compatible endpoint, or an eve endpoint you operate. The key is encrypted before storage and decrypted only in memory, for the duration of a call. When you ask for an AI action — a mention, a review pass, a generated card — the relevant content is sent to that provider, and from that point the provider's terms and privacy policy govern it. We have no contract with a provider you chose. Check whether your provider account has training disabled.
- eve, on plan credits
- eve is our own AI service, paid from a prepaid AI balance: Pro and Team include a monthly amount, and you can buy prepaid credits separately from your membership. When you use it, the content of your request travels through our eve gateway to the AI model providers eve runs on, under our contracts with them — which exclude training on your content. Credits meter the model tokens you actually use. If your organisation has no credits and no connected provider, AI features simply do not run.
Either way, AI processing happens only when someone in your workspace asks for it — a mention, a review request, a generated card. Nothing is sent to any AI provider in the background. The model providers behind eve are listed on the sub-processor page (/legal/subprocessors); a provider you connect yourself is your processor, not ours, and is deliberately not on that list.
9Why we process it, and on what basis
| What | Purpose | Lawful basis (GDPR Art. 6) |
|---|---|---|
| Email, name, sessions, passkeys, tokens | Give you an account and keep it secure | Contract, Art. 6(1)(b) |
| Organisation, workspace, membership, roles | Provide the service you signed up for | Contract, Art. 6(1)(b) |
| Workspace content and blobs | Store and serve what you put in | Contract, Art. 6(1)(b), on your instructions as processor |
| Recorded sessions | Store, replay and project them | Contract, Art. 6(1)(b); you are the controller for what they contain |
| Connected-app grants, codes and tokens | Let the assistant you authorised act on your workspace, within its scope | Contract, Art. 6(1)(b) |
| Security audit trail (consents, revocations, denials, with IP and user agent) | Detect and reconstruct token theft and abuse; give admins accountability over connections | Legitimate interest, Art. 6(1)(f) — the interest is the security of your workspace and our platform |
| Stripe customer and subscription identifiers | Take payment, issue invoices | Contract, Art. 6(1)(b); legal obligation for tax records, Art. 6(1)(c) |
| Invitations and waitlist entries | Let admins seat people; manage a staged launch | Contract and legitimate interest, Art. 6(1)(b) and (f) |
| Notifications you switched on | Tell you about activity you asked to hear about | Contract, Art. 6(1)(b); consent for web push and Telegram, Art. 6(1)(a) |
| Server logs, error reports, rate limiting | Keep the service up, debug it, stop abuse | Legitimate interest, Art. 6(1)(f) |
| Self-hosted, cookieless product analytics | Understand which features are used | Legitimate interest, Art. 6(1)(f) — nothing is stored on or read from your device, so no ePrivacy consent is required |
| Service emails (verification, resets, invitations, billing, incidents) | Operate the account | Contract, Art. 6(1)(b) |
| AI processing via eve or your provider | Produce the output someone in your workspace asked for | Contract, Art. 6(1)(b) |
Email notifications are off by default; in-app notifications are on. We send no marketing email today; if we ever start, it will be consent-based with a working unsubscribe, and this policy will say so first.
10Cookies and local storage
The marketing pages (vitrinka.ai) set no cookies and load no analytics. The only things the site keeps in your browser are a theme choice and a seen-the-intro flag, both first-party, both functional, neither ever sent anywhere.
The application (app.vitrinka.ai) sets only what it needs to work. No advertising cookies, no cross-site trackers:
| Name | Purpose | Lifetime |
|---|---|---|
vitrinka_session | Keeps you signed in | 30 days |
vitrinka_pending | Carries an email-verification step between two page loads | 10 minutes |
vitrinka_return_to | Sends you back where you were after signing in | 10 minutes |
vitrinka_webauthn | Holds one passkey ceremony together | 5 minutes |
vshare | Carries a share-link secret so the board's requests work without the URL parameter | 7 days |
vshareok | Proof that a share-link passphrase was entered correctly | 7 days |
- All of these are strictly necessary and set only when you sign in or open a share link, which is why there is no consent banner: there is nothing on either host that would require one.
vshareandvshareokare set withSameSite=None; Secure; Partitionedso a board embedded in another site keeps working.- The application also uses local storage and IndexedDB in your browser for offline queuing and UI state. That data stays on your device.
- Share links are served from https://share.vitrinka.ai, which never receives your session cookie.
11Who else touches the data
The authoritative, always-current list of sub-processors — each with its legal entity, role, location and transfer safeguard — is published at /legal/subprocessors, and organisation owners are emailed at least 30 days before a new one is added. The short version:
| Sub-processor | What for | Where |
|---|---|---|
| Hetzner Online GmbH | Servers and object storage | Germany and Finland |
| Amazon Web Services (SES) | Transactional email: verification, resets, invitations, notifications | EU (Frankfurt region) |
| Stripe Payments Europe / Stripe, Inc. | Subscriptions and payment | Ireland and United States |
| eve's model providers | AI output, only when your workspace uses eve credits | See the sub-processor page |
| Push services of Apple, Google and Mozilla | Delivering web push, if you enable it | Depends on your browser |
| Telegram | Notifications, only if you link a chat | Outside the EU |
| GitHub, Inc. | GitHub sign-in, if you use it; commit metadata and, when you file an issue from a board, the issue title and text derived from your annotation — only if you connect the GitHub app | United States |
- An AI provider your organisation connects with its own key is your processor, not our sub-processor — you chose it, your contract with it governs, and that is why it is not in the table.
- An AI assistant you connect to a workspace (section 7) is likewise your recipient: what its tool calls return goes to the provider you connected — Anthropic, OpenAI, or your MCP client's vendor — under that provider's policy.
- Sentry (error tracking) and umami (analytics) run on our own infrastructure and are not third-party processors.
We also disclose data when we are legally required to, and when it is necessary to establish or defend legal claims.
12How long we keep things
| Data | Retention |
|---|---|
Account (users) | While the account exists, then erased on deletion |
| Workspace content and blobs | While the workspace exists. Deleting a workspace destroys its encryption key, which makes its stored content permanently unreadable at once — see section 15. |
| Browser sessions | 30 days from creation; expired rows are deleted when next touched |
| Share links | Until they expire or you revoke them; the default is 30 days |
| Invitations | Until accepted, revoked or expired; settled invitations are erased 12 months later |
| Waitlist entries | 12 months |
| Recorded sessions | Deletion is soft for a 30-day grace window (restorable), then a sweeper permanently destroys the session — events, screenshots, replay streams and derived artifacts |
| Card trash | Deleted cards are restorable for 30 days, then purged permanently — including their uploads, annotation snapshots and thread attachments. Boards are archived, not trashed: archiving hides a board and is always reversible. |
| Notifications | 90 days |
| API tokens | Until revoked |
| Connected-app tokens and grants | Access tokens 1 hour; refresh tokens at most 180 days, rotating; grants until revoked — by you, an admin, an automatic security revocation, or your membership ending. Unused app registrations 30 days. |
| Security audit trail | For the life of the organisation — it is an append-only security record |
| Server logs and error reports | At most 90 days |
| Product analytics | Aggregated, cookieless statistics with no persistent identifier; kept as statistics |
| Billing records | 10 years, as Czech accounting and tax law requires |
| Backups | Encrypted backup archives rotate out after 30 days. Deleted data can persist inside a backup for at most that window — except workspace deletion, whose key destruction makes the content unreadable even in earlier backups' blobs; see section 15. |
13Deleting your account, and getting a copy
Deleting an account removes the user record and the workspaces that are left without an owner. For each such workspace that means its encryption key is destroyed and its entire database file and object-storage prefix — boards, screenshots, uploads, artifacts, recorded sessions, everything — becomes permanently unreadable, then physically removed.
There is no self-serve deletion button yet, and no one-click export archive. Until they ship: write to privacy@vitrinka.ai from your account email, and we complete deletion, or hand you a machine-readable copy of your data, within one month. What you can already do yourself: export sets as zip archives, and read board and library content through the documented API with your own token.
Data that survives deletion: invoices and payment records we are legally required to keep, and content that other members of a shared workspace still own.
14Your rights
Under GDPR you can ask us to:
- Access
- the personal data we hold about you, and get a copy.
- Correct
- it if it is wrong. Name and email can be changed in the product.
- Erase
- it. See section 13.
- Restrict or object to
- processing based on legitimate interest, on grounds relating to your particular situation.
- Port
- it: receive it in a structured, commonly used, machine-readable format.
- Withdraw consent
- you gave, for example for web push or Telegram — turning the channel off in your notification settings does this.
- You can do a lot of this yourself: revoke tokens, connected apps and share links, remove passkeys, leave a workspace, change notification preferences, export sets as zip archives, and read board and library content through the API with your own token.
- For anything else, write to privacy@vitrinka.ai. We answer within one month, and will tell you if we need longer for a complex request.
- If the data concerns content inside someone else's workspace, we are the processor. Ask the workspace's organisation — they are the controller. We will help them respond.
You can complain to the Czech supervisory authority: Úřad pro ochranu osobních údajů, Pplk. Sochora 27, 170 00 Praha 7, https://uoou.gov.cz. You can also complain to the authority where you live.
15International transfers
Hosting, storage, email and analytics stay in the European Union: Hetzner data centres in Germany and Finland, transactional email through AWS's Frankfurt region, error tracking and analytics on our own EU servers.
Some optional or billing-side providers involve transfers outside the EU — Stripe (payments), GitHub (only if you sign in with it), Telegram (only if you link a chat), and Apple/Google/Mozilla push services (only if you enable web push). These rely on the safeguards named per provider on the sub-processor page: EU–US Data Privacy Framework certification or Standard Contractual Clauses.
When you connect an AI provider or an AI assistant yourself, content you send goes wherever that provider processes it. You choose the provider, so you choose that transfer.
16Security
The full, current description of our security measures — encryption, isolation, key handling, backups, disclosure — is published at /legal/security. The load-bearing points:
- Each workspace has its own database file and its own object-storage key prefix. Isolation is physical, not a
WHEREclause. - Encryption at rest is per workspace, and it is complete. Every workspace's stored files and its most sensitive database content (recorded-session events, annotation text, project memory, documents, frozen share snapshots) are encrypted with that workspace's own AES-256-GCM data key before they touch disk or object storage — verified across every stored object. The production data volume additionally sits on LUKS2 full-disk encryption bound to our private network.
- Deleting a workspace destroys its key. That makes its encrypted content permanently unreadable at once — in live storage, in caches, and in every backup's content blobs. Backup archives themselves are encrypted end-to-end under the same key hierarchy and rotate out after 30 days.
- Passwords are held only as argon2id hashes; passkeys as public credentials. API tokens, connector tokens, session cookies and share-link secrets are stored as hashes. Secrets that hurt when leaked — AI provider keys, share-link secrets — are encrypted under a master key held by the server process, bound to the record they belong to.
- Sign-in, sign-up, verification, reset, passkey and connector-authorisation attempts are rate limited. All traffic is over TLS. Share links live on a separate host that never accepts sessions or API tokens. Uploaded HTML is served sandboxed under a restrictive content security policy.
- Access to production is limited to the people who operate it, and we do not read workspace content as a matter of routine.
If we suffer a personal-data breach, we notify the supervisory authority within 72 hours of becoming aware of it where GDPR requires it, and we inform affected workspace owners (as controllers) without undue delay.
17Children
vitrinka is a product for professional use. It is not directed at children and we do not knowingly collect data from anyone under 16. If you believe a child has an account, write to the privacy contact and we will remove it.
18Changes to this policy
We update this policy when the product changes. Material changes are announced by email to account owners and in the product at least 30 days before they take effect. The date at the top always tells you which version you are reading.
19Contact
Privacy: privacy@vitrinka.ai. Everything else: hello@vitrinka.ai.
Postal: LEFTEQ s.r.o., Herálecká IV 1583/4, Krč, 140 00 Praha 4, Czech Republic.