Privacy policy, terms of service, cookie policy + a cookie notice
Three plain-language documents in both app languages (lib/legal.ts, rendered by components/LegalPage.tsx): /privacy describes the local-first storage, the key never leaving the browser and the three opt-in server copies (sync, reminders, reports); /terms covers the GPL-3.0-only software, your own Ollama key, fair use and liability; /cookies states what is true — no cookies at all (no Set-Cookie, no document.cookie), strictly-necessary local storage instead, no tracking. A cookie notice tells every new browser the same thing once and remembers the dismissal (freezmo.consent.v1). It sits at z-44: below the immersive study feeds so it can never cover a session, above the phone tab bar. Settings links all three documents. The regression suite checks the pages render with real sections and that dismissing the notice sticks. Version 0.1.7, SW -> freezmo-v53.
This commit is contained in:
parent
df34337b4a
commit
464781a7fd
13 changed files with 583 additions and 2 deletions
|
|
@ -997,6 +997,15 @@ const en: Record<string, string> = {
|
|||
"chat.savedToNotes": "Saved to {deck}'s notes",
|
||||
"chat.savedToNotesTrimmed": "Saved to {deck}'s notes (trimmed to fit)",
|
||||
"chat.savedFromChat": "Saved from chat",
|
||||
"legal.updated": "Last updated {when}",
|
||||
"legal.privacy": "Privacy policy",
|
||||
"legal.terms": "Terms of service",
|
||||
"legal.cookies": "Cookie policy",
|
||||
"settings.legal": "Legal",
|
||||
"consent.title": "About cookies",
|
||||
"consent.body": "Freezmo uses no cookies and no trackers — your decks, homework and settings stay in this browser.",
|
||||
"consent.link": "Cookie policy",
|
||||
"consent.ok": "Got it",
|
||||
"settings.version": "Version",
|
||||
"settings.chatNotes": "Keep notes text for chat",
|
||||
"settings.chatNotesNote": "Chat answers from the notes you added (stored with each deck). Turn off to use only the generated study content.",
|
||||
|
|
@ -1940,6 +1949,15 @@ const cs: Record<string, string> = {
|
|||
"chat.savedToNotes": "Uloženo do poznámek sady {deck}",
|
||||
"chat.savedToNotesTrimmed": "Uloženo do poznámek sady {deck} (zkráceno, aby se vešlo)",
|
||||
"chat.savedFromChat": "Uloženo z chatu",
|
||||
"legal.updated": "Naposledy upraveno {when}",
|
||||
"legal.privacy": "Zásady soukromí",
|
||||
"legal.terms": "Podmínky použití",
|
||||
"legal.cookies": "Zásady cookies",
|
||||
"settings.legal": "Právní informace",
|
||||
"consent.title": "O cookies",
|
||||
"consent.body": "Freezmo nepoužívá cookies ani sledování — sady, úkoly a nastavení zůstávají v tomto prohlížeči.",
|
||||
"consent.link": "Zásady cookies",
|
||||
"consent.ok": "Rozumím",
|
||||
"settings.version": "Verze",
|
||||
"settings.chatNotes": "Uchovávat text poznámek pro chat",
|
||||
"settings.chatNotesNote": "Chat odpovídá z poznámek, které jsi přidal (jsou uložené u každé sady). Vypnutím bude používat jen vygenerovaný obsah.",
|
||||
|
|
|
|||
296
lib/legal.ts
Normal file
296
lib/legal.ts
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
/**
|
||||
* Privacy policy, terms of service and cookie policy — in both app languages.
|
||||
*
|
||||
* Written to describe what this app *actually* does (local-first storage, the
|
||||
* key never leaving the browser, opt-in server copies), not a template. The
|
||||
* pages that render this live in app/privacy, app/terms and app/cookies; the
|
||||
* cookie banner links to the same text. Keep them in step with the code.
|
||||
*/
|
||||
|
||||
export type LegalSection = {
|
||||
heading: string;
|
||||
paragraphs: string[];
|
||||
list?: string[];
|
||||
};
|
||||
|
||||
export type LegalDocument = {
|
||||
title: string;
|
||||
updated: string;
|
||||
intro: string;
|
||||
sections: LegalSection[];
|
||||
footer: string;
|
||||
};
|
||||
|
||||
const UPDATED = "October 2026";
|
||||
|
||||
const PRIVACY_EN: LegalDocument = {
|
||||
title: "Privacy policy",
|
||||
updated: UPDATED,
|
||||
intro:
|
||||
"Freezmo is a self-hosted study app with no accounts. This page describes exactly what happens to your data — nothing here is boilerplate.",
|
||||
sections: [
|
||||
{
|
||||
heading: "Everything lives in your browser",
|
||||
paragraphs: [
|
||||
"Your decks, folders, homework, chats, study history and settings are stored in this browser (localStorage and IndexedDB). Nothing is uploaded unless you switch on one of the opt-ins below.",
|
||||
"Clearing the site data deletes it. Settings → Export all data gives you a complete copy at any time.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Your Ollama API key",
|
||||
paragraphs: [
|
||||
"The key is kept in this browser only. It is sent to this Freezmo server for the single model call you asked for, forwarded to Ollama, and forgotten: never written to disk, never logged, never part of a backup, sync payload or share link.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "What the server stores — only if you opt in",
|
||||
paragraphs: ["There is no other server-side data. Each of these is off until you turn it on:"],
|
||||
list: [
|
||||
"Sync — an encrypted blob the server cannot read (the key stays in your browser). Revocable from Settings → Delete synced data.",
|
||||
"Reminders — the push endpoint your browser gave us, its keys and a timestamp. No personal data, no history.",
|
||||
"Reported questions — the question text, the deck and activity ids and a timestamp. These are how bad AI cards get fixed; they are the one thing an operator can read.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "What the server does not store",
|
||||
paragraphs: [
|
||||
"No accounts, no email addresses, no analytics, no cookies, no tracking. The rate limiter keeps a client IP address in memory for a few minutes to stop floods and never writes it to disk.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Third parties",
|
||||
paragraphs: [
|
||||
"Model calls go to the Ollama endpoint this instance is configured for, using your key — Ollama's own privacy terms apply to them. Reminders travel through your browser's push service (Google, Mozilla or Apple). There is nothing else: no ads, no analytics, no embeds.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Your choices",
|
||||
paragraphs: [
|
||||
"Delete the local copy by clearing the site data (or Settings). Revoke the synced copy from Settings. Turn reminders off from Settings. If you want a reported question removed from the operator's file, ask the person running this instance — it is their file.",
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: "Plain-language description of how this app handles data — not legal advice.",
|
||||
};
|
||||
|
||||
const PRIVACY_CS: LegalDocument = {
|
||||
title: "Zásady ochrany soukromí",
|
||||
updated: "říjen 2026",
|
||||
intro:
|
||||
"Freezmo je samoobslužná studijní aplikace bez účtů. Tahle stránka popisuje, co se přesně děje s tvými daty — nic z toho není šablona.",
|
||||
sections: [
|
||||
{
|
||||
heading: "Všechno zůstává v tvém prohlížeči",
|
||||
paragraphs: [
|
||||
"Sady, složky, úkoly, chaty, historie učení i nastavení jsou uložené v tomto prohlížeči (localStorage a IndexedDB). Nic se neodesílá, dokud nezapneš některou z níže uvedených voleb.",
|
||||
"Smazáním dat stránky je smažeš. Nastavení → Exportovat všechna data ti kdykoli dá úplnou kopii.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Tvůj API klíč Ollama",
|
||||
paragraphs: [
|
||||
"Klíč je uložený jen v tomto prohlížeči. Posílá se tomuto serveru Freezmo pro jeden požadovaný modelový dotaz, server ho předá Ollamě a zapomene ho: nikdy se neukládá na disk, neloguje se a není součástí zálohy, synchronizace ani sdíleného odkazu.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Co server ukládá — jen když to zapneš",
|
||||
paragraphs: ["Jiná data na serveru nejsou. Každá z těchhle věcí je vypnutá, dokud ji nezapneš:"],
|
||||
list: [
|
||||
"Synchronizace — zašifrovaný blob, který server nedokáže přečíst (klíč zůstává v prohlížeči). Zrušitelný v Nastavení → Smazat synchronizovaná data.",
|
||||
"Připomínky — push endpoint, který ti dal prohlížeč, jeho klíče a časové razítko. Žádná osobní data, žádná historie.",
|
||||
"Nahlášené otázky — text otázky, ID sady a aktivity a časové razítko. Díky nim se opravují špatné AI kartičky; je to jediná věc, kterou provozovatel může číst.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Co server neukládá",
|
||||
paragraphs: [
|
||||
"Žádné účty, e-maily, analytiku, cookies ani sledování. Omezovač rychlosti drží IP adresu klienta pár minut v paměti, aby zastavil záplavy požadavků, a nikdy ji nezapisuje na disk.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Třetí strany",
|
||||
paragraphs: [
|
||||
"Modelové dotazy jdou na Ollama endpoint, který je tato instance nastavená používat, a to s tvým klíčem — platí na ně vlastní podmínky Ollamy. Připomínky putují přes push službu tvého prohlížeče (Google, Mozilla nebo Apple). Nic jiného tu není: žádné reklamy, analytika ani vložený obsah.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Tvoje volby",
|
||||
paragraphs: [
|
||||
"Lokální kopii smažeš smazáním dat stránky (nebo v Nastavení). Synchronizovanou kopii zrušíš v Nastavení. Připomínky vypneš v Nastavení. Pokud chceš, aby provozovatel odstranil nahlášenou otázku ze svého souboru, řekni mu to — ten soubor je jeho.",
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: "Popis v lidské řeči, jak aplikace nakládá s daty — není právní rada.",
|
||||
};
|
||||
|
||||
const TERMS_EN: LegalDocument = {
|
||||
title: "Terms of service",
|
||||
updated: UPDATED,
|
||||
intro:
|
||||
"Freezmo is free software (GPL-3.0-only) that someone is hosting for you — usually a friend or yourself. These are the house rules for using that instance.",
|
||||
sections: [
|
||||
{
|
||||
heading: "The software comes as-is",
|
||||
paragraphs: [
|
||||
"Freezmo is provided under the GNU General Public License v3 only, without warranty of any kind to the extent the law allows. AI output can be wrong: read it before you hand it in — that is what the note under every card is for.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Your key, your usage",
|
||||
paragraphs: [
|
||||
"You bring your own Ollama API key. Limits, costs and account standing are between you and Ollama. Never paste a key you do not own, and keep your own key to yourself.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Fair use of the instance",
|
||||
paragraphs: [
|
||||
"Don't flood it, don't try to break it and don't use it to attack anything else. The operator can rate-limit, block or shut the instance down at any time, and the app already refuses obvious abuse.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Your content",
|
||||
paragraphs: [
|
||||
"Your notes, decks, homework and chats are yours. They stay in your browser, so the operator cannot read them — the only exception is a question you report on purpose (see the privacy policy).",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Availability and changes",
|
||||
paragraphs: [
|
||||
"This instance is a courtesy, with no uptime promise. The app and these terms may change; the current version always lives in the app, linked from Settings.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Liability",
|
||||
paragraphs: [
|
||||
"To the extent permitted by law, the operator and the authors are not liable for anything this app does or fails to do — including lost study time, lost data or a wrong answer in your homework.",
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: "Plain-language terms for a self-hosted app — not legal advice.",
|
||||
};
|
||||
|
||||
const TERMS_CS: LegalDocument = {
|
||||
title: "Podmínky použití",
|
||||
updated: "říjen 2026",
|
||||
intro:
|
||||
"Freezmo je svobodný software (GPL-3.0-only), který ti někdo hostuje — většinou kamarád nebo ty sám. Tohle jsou pravidla pro používání téhle instance.",
|
||||
sections: [
|
||||
{
|
||||
heading: "Software je tak, jak je",
|
||||
paragraphs: [
|
||||
"Freezmo se poskytuje pod licencí GNU General Public License v3 only, bez jakékoli záruky v rozsahu, který zákon dovoluje. AI výstup může být špatně: než ho odevzdáš, přečti si ho — od toho je poznámka pod každou kartičkou.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Tvůj klíč, tvoje spotřeba",
|
||||
paragraphs: [
|
||||
"Používáš vlastní API klíč Ollama. Limity, náklady a stav účtu jsou mezi tebou a Ollamou. Nikdy nevkládej klíč, který ti nepatří, a ten svůj nikomu nedávej.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Férové používání instance",
|
||||
paragraphs: [
|
||||
"Nezahlcuj ji, nezkoušej ji rozbít a nepoužívej ji k útoku na něco jiného. Provozovatel může kdykoli omezit rychlost, zablokovat přístup nebo instanci vypnout; aplikace už sama odmítá zjevné zneužití.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Tvůj obsah",
|
||||
paragraphs: [
|
||||
"Poznámky, sady, úkoly a chaty jsou tvoje. Zůstávají v tvém prohlížeči, takže je provozovatel nemůže číst — jediná výjimka je otázka, kterou sám nahlásíš (viz zásady soukromí).",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Dostupnost a změny",
|
||||
paragraphs: [
|
||||
"Instance je zdvořilost, bez slibu dostupnosti. Aplikace i tyhle podmínky se mohou měnit; aktuální verze je vždy v aplikaci, odkaz v Nastavení.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Odpovědnost",
|
||||
paragraphs: [
|
||||
"V rozsahu, který zákon dovoluje, provozovatel ani autoři neodpovídají za nic, co aplikace udělá nebo neudělá — včetně ztraceného času na učení, ztracených dat nebo špatné odpovědi v úkolu.",
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: "Podmínky v lidské řeči pro samoobslužnou aplikaci — nejsou právní rada.",
|
||||
};
|
||||
|
||||
const COOKIES_EN: LegalDocument = {
|
||||
title: "Cookie policy",
|
||||
updated: UPDATED,
|
||||
intro: "Short version: Freezmo sets no cookies at all. This page exists because the law asks for one, and because it is worth being explicit.",
|
||||
sections: [
|
||||
{
|
||||
heading: "No cookies",
|
||||
paragraphs: [
|
||||
"The server sends no Set-Cookie header and the app never touches document.cookie. There are no third-party embeds, no pixels and no tag managers.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Local storage instead",
|
||||
paragraphs: [
|
||||
"The app keeps your data in localStorage and IndexedDB — the same idea as a cookie, except it is never sent to the server automatically. It is strictly necessary for the app to work (it *is* the app's storage), which is why it does not need consent; the banner only tells you it happens.",
|
||||
],
|
||||
list: [
|
||||
"Settings: language, theme, daily goal, haptics, chat notes preference.",
|
||||
"Content: decks, folders, homework, chats, study history and schedule.",
|
||||
"Bookkeeping: the sync id, the last-synced time, which questions you reported, whether you dismissed this banner.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "No tracking, no analytics, no ads",
|
||||
paragraphs: ["Nothing measures you, and nothing is sold. The only counters the app keeps are the rate limits on the server, held in memory."],
|
||||
},
|
||||
{
|
||||
heading: "Clearing it",
|
||||
paragraphs: [
|
||||
"Clear the site data in your browser to wipe the local copy, or use Settings → Export all data first if you want a backup. The opt-in server copies (sync, reminders, reports) are described in the privacy policy.",
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: "Plain-language description of what this app stores in your browser — not legal advice.",
|
||||
};
|
||||
|
||||
const COOKIES_CS: LegalDocument = {
|
||||
title: "Zásady používání cookies",
|
||||
updated: "říjen 2026",
|
||||
intro: "Krátce: Freezmo nepoužívá žádné cookies. Tahle stránka existuje proto, že to zákon vyžaduje — a protože je dobré to říct napřímo.",
|
||||
sections: [
|
||||
{
|
||||
heading: "Žádné cookies",
|
||||
paragraphs: [
|
||||
"Server neposílá hlavičku Set-Cookie a aplikace se nikdy nedotkne document.cookie. Nejsou tu žádné vložené prvky třetích stran, pixely ani správci značek.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Místo toho lokální úložiště",
|
||||
paragraphs: [
|
||||
"Aplikace drží tvá data v localStorage a IndexedDB — stejná myšlenka jako cookie, jen se nikdy neposílají serveru automaticky. Je to nezbytné pro fungování aplikace (je to *její* úložiště), a proto to nepotřebuje souhlas; banner ti to jen oznamuje.",
|
||||
],
|
||||
list: [
|
||||
"Nastavení: jazyk, téma, denní cíl, haptika, preference poznámek pro chat.",
|
||||
"Obsah: sady, složky, úkoly, chaty, historie a plán učení.",
|
||||
"Evidence: sync ID, čas poslední synchronizace, které otázky jsi nahlásil, jestli jsi zavřel tenhle banner.",
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: "Žádné sledování, analytika ani reklamy",
|
||||
paragraphs: ["Nic tě neměří a nic se neprodává. Jediné počítadla jsou limity rychlosti na serveru, držené v paměti."],
|
||||
},
|
||||
{
|
||||
heading: "Jak to smazat",
|
||||
paragraphs: [
|
||||
"Smaž data stránky v prohlížeči, nebo si nejdřív udělej kopii přes Nastavení → Exportovat všechna data. Volitelné kopie na serveru (synchronizace, připomínky, hlášení) popisují zásady soukromí.",
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: "Popis v lidské řeči, co aplikace ukládá v prohlížeči — není právní rada.",
|
||||
};
|
||||
|
||||
export type LegalSlug = "privacy" | "terms" | "cookies";
|
||||
|
||||
export const LEGAL: Record<LegalSlug, { en: LegalDocument; cs: LegalDocument }> = {
|
||||
privacy: { en: PRIVACY_EN, cs: PRIVACY_CS },
|
||||
terms: { en: TERMS_EN, cs: TERMS_CS },
|
||||
cookies: { en: COOKIES_EN, cs: COOKIES_CS },
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue