1. Навіщо взагалі потрібні Privacy Policy, Terms і Support
Почнімо з неприємної правди: для ChatGPT Store наявність публічної політики конфіденційності та контактів підтримки — не просто «гарний тон», а жорстка вимога. У настановах OpenAI прямо сказано, що кожен застосунок має мати опубліковану Privacy Policy, у якій чітко пояснено, які дані збираються і як вони використовуються, а також має бути контакт для підтримки.
Але річ не лише в тому, щоб «задовольнити модерацію». Ці документи розвʼязують одразу кілька завдань.
По‑перше, це базовий рівень довіри для користувача. Людина бачить, що за застосунком стоять живі люди або компанія, є правила гри й є місце, куди можна звернутися з проблемою. У світі, де «черговий сервіс із ШІ» зʼявляється щодня, це вже конкурентна перевага.
По‑друге, це формалізація того, що ви вже заклали в архітектуру. Усе, що ви продумували в модулях про безпеку, журналювання, строки зберігання (retention), видалення даних і роботу з платежами, потрібно відобразити й словами. Якщо ви обіцяєте «не зберігаємо переписку», але водночас журналюєте весь tool‑input назавжди, це не просто неохайно — це привід для серйозних претензій.
По‑третє, це ще один рівень контракту між вами та OpenAI. Store фактично каже: «Ми готові показувати ваш застосунок мільйонам людей, але ви маєте чесно описати, що робите з їхніми даними, і бути на звʼязку, якщо щось піде не так».
Підсумуймо: юридичні сторінки — не про «юристи змусили». Це спосіб синхронізувати очікування: що робить застосунок, яких даних він торкається, яку відповідальність ви готові на себе взяти й як користувач може з вами звʼязатися.
2. Де «живуть» ці юридичні URL у ChatGPT App
Технічно для застосунку ChatGPT юридичні сторінки — це звичайні публічні URL‑адреси, які ви вказуєте в метаданих застосунку та в лістингу Store. У настановах їх зазвичай називають чимось на кшталт privacy_policy_url, terms_of_service_url і контактом підтримки (support).
Ці URL‑адреси мають відповідати кільком простим, але важливим умовам:
- Вони «живуть» на стабільному домені вашого продукту або компанії. Жодних тимчасових ngrok‑посилань — інакше за тиждень Store поведе користувача в нікуди.
- Вони доступні без авторизації. Користувач (і ревʼюер) мають відкрити їх у браузері без входу в обліковий запис і зайвих ритуалів.
- Вони актуальні й відповідають реальності. Якщо ви змінюєте архітектуру обробки даних, з часом доведеться оновлювати й текст.
У нашому навчальному проєкті GiftGenius уже є фронтенд на Next.js, який ми деплоїмо, скажімо, на Vercel. Отже, найлогічніше місце для юридичних сторінок — маршрути такого вигляду:
- /legal/privacy
- /legal/terms
- /support
По суті, це просто ще три сторінки в застосунку. Саме на них ви посилатиметеся у формі подання застосунку на ревʼю.
3. Privacy Policy: як чесно описати, що ви робите з даними
Роль Privacy Policy
Privacy Policy (політика конфіденційності; далі для стислості — Policy) відповідає на головне запитання: «Що цей застосунок робить із моїми даними?» Вона має описувати, які категорії даних ви обробляєте, звідки вони беруться, навіщо вам потрібні, де й як довго зберігаються, кому передаються та як користувач може попросити їх видалити.
Особливість ChatGPT Apps у тому, що користувачеві важливо розуміти, що саме ви отримуєте з чату. OpenAI окремо підкреслює: ваш застосунок не має намагатися відновити весь діалог, а повинен працювати лише з тими фрагментами, які модель або користувач явно надіслали в інструменти. Це теж варто зазначити в Policy.
Починаємо не з тексту, а з архітектури
Перш ніж писати бодай одне юридичне слово, корисно подивитися на свій застосунок очима SRE/архітектора: які дані насправді проходять через систему.
Для нашого прикладу — GiftGenius — це може виглядати приблизно так:
| Категорія даних | Звідки надходить | Де зберігається | Строк/поведінка |
|---|---|---|---|
| Текст запиту (фрагмент/snippet із чату) | tool‑виклик від ChatGPT | Журнали запитів у бекенді | N днів або видаляємо одразу |
| Подарунки, обрані користувачем | Дії у віджеті | База GiftGenius | Зберігаємо до видалення облікового запису |
| Адреса електронної пошти користувача (якщо є OAuth) | Провайдер автентифікації | База користувачів | Поки обліковий запис активний |
| Технічні метрики (IP, часова мітка/timestamp, помилки) | HTTP‑запити | Журнали / система моніторингу | N днів за політикою журналів |
Таку таблицю можна завести прямо в документації проєкту (наприклад, у /docs): вона знадобиться і для розробки, і для модуля Security, і для самої Policy.
Далі цю структуру «перекладаємо» на людську мову.
Структура Privacy Policy для GiftGenius
У навчальному проєкті не потрібно писати епос на 20 сторінок — достатньо компактної, але чесної структури. Зазвичай виділяють кілька розділів:
- Вступ: хто ви та що це за застосунок.
- Які дані ви збираєте.
- Як ви їх використовуєте.
- Кому передаєте.
- Де й як довго зберігаєте.
- Права користувача (зокрема запит на видалення).
- Контакти з питань приватності.
Важливо розуміти: навіть для навчального проєкту це не просто «риба». У модулі про безпеку ви вже продумували строки зберігання журналів, політику видалення, резервні копії — тепер це потрібно акуратно сформулювати.
Найпростіша реалізація сторінки в Next.js
Давайте зробимо сторінку /legal/privacy у нашому застосунку. В App Router це буквально один файл:
// app/legal/privacy/page.tsx
export default function PrivacyPage() {
return (
<main className="mx-auto max-w-3xl p-8 prose">
<h1>Privacy Policy – GiftGenius</h1>
<p>Останнє оновлення: {new Date().toLocaleDateString()}</p>
{/* далі йдуть розділи політики */}
</main>
);
}
Цей приклад навмисно простий: мета — зафіксувати статичний URL. У реальному проєкті текст політики майже завжди зберігають окремо (наприклад, у .md‑файлі) і підвантажують, щоб не розмазувати тонни тексту по JSX.
Наприклад, можна зробити типовий loader:
// app/legal/privacy/page.tsx
import policyHtml from "./policy.html"; // заздалегідь зібраний HTML
export default function PrivacyPage() {
return (
<main
className="mx-auto max-w-3xl p-8 prose"
dangerouslySetInnerHTML={{ __html: policyHtml }}
/>
);
}
Коментарі в стилі «не повторюйте це без розуміння» тут доречні: dangerouslySetInnerHTML безпечний лише тоді, коли ви контролюєте джерело HTML (наприклад, збираєте його самі з markdown у CI).
Звʼязок із реальними процесами
Найважливіше: не можна написати в Policy те, чого у вас немає в коді. Якщо ви заявляєте, що:
- не зберігаєте текст запитів довше 7 днів;
- на запит користувача повністю видаляєте його профіль;
- не використовуєте ці дані для навчання своїх моделей,
то у вас мають бути:
- налаштування строків зберігання (retention) у журналах;
- ендпойнт або адміністративний процес видалення користувача;
- відсутність коду, який зливає журнали у стороннє сховище «для Data Science».
І навпаки: якщо ви ввімкнули метрики використання, A/B‑експерименти чи аналітику за країнами, про це потрібно чесно сказати в Policy. І надати користувачеві принаймні базові права: дізнатися, що зберігається, і запросити видалення.
З даними й Privacy Policy розібралися. Тепер залишилося зафіксувати не тільки обробку даних, а й самі «правила гри» — це завдання Terms.
4. Terms of Use / Service: правила гри та дисклеймери щодо ШІ
Навіщо потрібні Terms, якщо вже є Policy
Privacy Policy відповідає на запитання «що ви робите з даними». Terms of Use/Service (далі — Terms) — на запитання «на яких умовах узагалі можна користуватися застосунком». Це юридичний договір між вами та користувачем.
У ньому описують:
- що таке GiftGenius і які функції він надає;
- які дії користувача вважаються допустимими, а які — ні;
- де проходять «межі магії» ШІ (AI‑дисклеймери);
- які у вас обмеження відповідальності;
- як розвʼязуються спори та яка юрисдикція застосовується.
Для застосунку із ШІ особливо важливі два моменти: дисклеймер щодо точності та обмеження відповідальності.
ШІ‑специфіка: «модель може помилятися»
Наш GiftGenius дає рекомендації щодо подарунків. Це мило й відносно безпечно, але навіть тут можна «наступити на граблі»: користувач попросив «подарунок для людини з алергією на горіхи», модель згенерувала щось не те, людина постраждала — і всім погано.
Зрозуміло, що Terms не є бронежилетом від усіх ризиків, але вони чітко фіксують:
- що результати генерує ШІ й вони можуть бути неточними, застарілими або просто дивними;
- що користувач зобовʼязаний самостійно перевіряти важливу інформацію, особливо повʼязану зі здоровʼям, фінансами та іншими чутливими сферами;
- що ви не даєте жодних гарантій «ідеальності» рекомендацій і не несете відповідальності за використання результату не за призначенням.
Формулювання згодом доведеться допрацьовувати з юристом, але технічному розробнику важливо розуміти сам принцип.
Комерційні нюанси
Якщо ваш застосунок виконує бодай якісь платіжні дії (модуль про ACP і commerce ви ще розбиратимете глибше, але в курсі це вже закладено), у Terms потрібно акуратно описати:
- через кого проходять платежі (Stripe, ACP, інша система);
- які дані про платежі ви взагалі бачите;
- які умови повернення та скасування замовлення;
- що саме вважається успішною транзакцією.
Загальна рекомендація платформи — прямо вказувати, що дані картки обробляє платіжний провайдер, а не ваш сервер, а ви зберігаєте лише мінімум (наприклад, ID транзакції).
Реалізація /legal/terms у Next.js
Технічно все дуже схоже на Privacy Policy. Створюємо сторінку:
// app/legal/terms/page.tsx
export default function TermsPage() {
return (
<main className="mx-auto max-w-3xl p-8 prose">
<h1>Terms of Use – GiftGenius</h1>
<p>Останнє оновлення: {new Date().toLocaleDateString()}</p>
{/* розділи: опис сервісу, обмеження, AI-дисклеймер, відповідальність */}
</main>
);
}
І, як і у випадку з Policy, краще тримати текст в окремому файлі або CMS, а в коді залишити мінімум розмітки.
Можна винести спільну обгортку для юридичних сторінок:
// app/legal/LegalLayout.tsx
export function LegalLayout(props: { title: string; children: React.ReactNode }) {
return (
<main className="mx-auto max-w-3xl p-8 prose">
<h1>{props.title}</h1>
<p>Останнє оновлення: {new Date().toLocaleDateString()}</p>
{props.children}
</main>
);
}
А далі використовувати її і для Policy, і для Terms. Це не про «красу коду», а про те, щоб ви не забули поставити дату оновлення й витримали єдиний стиль.
5. Support / Contact: куди користувачеві звертатися з проблемою
Мінімум і «гарний тон»
У настановах OpenAI зазначено, що в застосунку має бути зрозумілий спосіб звʼязатися з розробником із питань підтримки. Це може бути проста адреса електронної пошти, але вона має існувати, приймати листи й хоча б час від часу давати відповідь.
Мінімальний варіант для навчального проєкту:
- окрема сторінка /support з коротким описом і mailto:support@yourdomain.com.
Більш «дорослий» варіант:
- форма зворотного звʼязку;
- посилання на документацію або Help Center;
- можливо, посилання на Slack/Discord, якщо ви будуєте спільноту навколо продукту.
Сторінка /support у Next.js
Почнімо із зовсім простого варіанта:
// app/support/page.tsx
export default function SupportPage() {
return (
<main className="mx-auto max-w-xl p-8 prose">
<h1>GiftGenius Support</h1>
<p>
Якщо у вас є запитання або проблеми, напишіть нам на{" "}
<a href="mailto:support@giftgenius.app">support@giftgenius.app</a>.
</p>
</main>
);
}
Трохи більш просунутий варіант — додати просту форму:
// app/support/page.tsx
"use client";
export default function SupportPage() {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// тут буде виклик API, який надішле лист/тікет
};
return (
<main className="mx-auto max-w-xl p-8 prose">
<h1>GiftGenius Support</h1>
<form onSubmit={handleSubmit}>
<input name="email" placeholder="Ваша електронна пошта" className="border p-2 w-full" />
<textarea name="message" placeholder="Чим ми можемо допомогти?" className="border p-2 w-full mt-2" />
<button type="submit" className="mt-4 px-4 py-2 border rounded">
Надіслати
</button>
</form>
</main>
);
}
Навіть якщо ви не реалізуєте справжній бекенд для цієї форми в навчальному проєкті, сама наявність зрозумілого URL і структури сторінки вже наближає вас до вимог Store.
Звʼязок з інцидент‑менеджментом
Support‑сторінка — це не лише «куди писати, якщо все впало», а й частина вашої операційної картини. У пізніших модулях ви говоритимете про інциденти та операційне життя застосунку. Там Support‑сторінка стане «вхідними дверима» для користувачів: через неї приходять баг‑репорти, запитання, запити на видалення даних. Зараз важливо бодай зафіксувати, що такі двері існують і не ведуть у «404 Not Found».
6. Інтеграція юридичних сторінок у застосунок і лістинг
Єдина конфігурація URL усередині проєкту
Щоб не розмазувати «магічні рядки» з URL по коду, зручно завести просту конфігурацію:
// lib/appConfig.ts
export const legalLinks = {
privacy: "https://giftgenius.app/legal/privacy",
terms: "https://giftgenius.app/legal/terms",
support: "https://giftgenius.app/support",
} as const;
Ці ж URL ви використовуватимете:
- у налаштуваннях ChatGPT App (метадані);
- на лендингу продукту;
- у листах, якщо реалізуєте сповіщення електронною поштою.
Усередині віджета ви можете дати користувачеві швидкий доступ до цих сторінок через openExternal.
// всередині React‑віджета GiftGenius
import { legalLinks } from "../lib/appConfig";
function FooterLinks() {
const handleOpen = (url: string) => {
window.openai?.openExternal({ url }); // Apps SDK helper
};
return (
<footer className="mt-4 text-xs text-gray-500">
<button onClick={() => handleOpen(legalLinks.privacy)}>Privacy</button>
<span> · </span>
<button onClick={() => handleOpen(legalLinks.terms)}>Terms</button>
</footer>
);
}
У реальному коді віджета краще використовувати хук useOpenExternal з Apps SDK; тут для стислості показано прямий виклик через window.openai.
Так ви підвищуєте прозорість: користувач може з віджета в один клік перейти до юридичних документів, а не шукати їх десь у Store.
Потік користувача та ревʼюера
Подивімося на потік взаємодії у вигляді невеликої схеми:
flowchart TD A[Сторінка лістингу в ChatGPT Store] --> B[Користувач читає опис App] B --> C[Відкриває Privacy/Terms за посиланням] B --> D[Встановлює / починає використовувати App] D --> E[Запускає віджет GiftGenius] E --> F["За потреби натискає 'Support' або 'Privacy'"]
Ревʼюер ChatGPT Store проходить приблизно тим самим шляхом, тільки трохи підозріливіше. Він дивиться:
- що написано в лістингу;
- що обіцяють Policy і Terms;
- як поводиться застосунок у реальному сценарії;
- чи збігається поведінка з тим, що ви написали.
Якщо все чесно й передбачувано, шанси пройти ревʼю різко зростають.
7. Практична вправа для вашого App
Щоб не залишатися на рівні теорії, корисно просто зараз накидати чернетки документів для свого застосунку.
Підхід може бути таким.
Спочатку на рівні архітектури опишіть:
- які категорії даних ви обробляєте (текст запиту, замовлення, електронна пошта, метрики);
- чи зберігаєте ви текстові запити і якщо так — як довго;
- які зовнішні сервіси підʼєднано (хостинг, база, платіжна система, аналітика).
Після цього:
- Складіть структуру Privacy Policy з розділами «що збираємо», «навіщо», «куди передаємо», «як довго зберігаємо», «як видалити дані».
- Складіть структуру Terms: опис сервісу, правила використання, обмеження (заборонений контент і зловживання), AI‑дисклеймер, обмеження відповідальності, посилання на Policy.
- Зробіть /support‑сторінку з коротким текстом і адресою електронної пошти.
- Додайте в проєкт lib/appConfig.ts з URL юридичних сторінок і використовуйте їх у віджеті та в будь‑яких зовнішніх посиланнях.
Навіть якщо тексти поки що будуть зовсім чернетковими й ви плануєте «потім показати це юристу», ви вже виконаєте важливу роботу: повʼяжете технічну реалізацію з юридичним описом.
8. Типові помилки під час підготовки юридичних сторінок
Помилка № 1: копіювати випадкову політику конфіденційності з інтернету й не адаптувати її.
Іноді хочеться просто взяти першу‑ліпшу політику конфіденційності, замінити назву продукту й вважати завдання закритим. Проблема в тому, що такий текст майже напевно не збігається з вашою архітектурою. У ньому можуть бути розділи про мобільний застосунок, push‑сповіщення або конкретні аналітичні сервіси, яких у вас немає. Або навпаки — там нічого не сказано про MCP‑сервер, журнали інструментів і роботу через ChatGPT. Ревʼюер помітить розбіжності, а користувачі відчують, що текст «про когось іншого».
Помилка № 2: обіцяти в Policy те, чого не реалізовано в коді.
Класичний приклад — фраза «ми видаляємо всі ваші дані за першою вимогою», тоді як у коді немає ні ендпойнта для видалення, ні навіть механізму, щоб знайти дані конкретного користувача. Те саме стосується строків зберігання журналів і фраз «ми не зберігаємо текст ваших повідомлень», якщо ви насправді складаєте tool‑input у систему журналювання без retention. Така невідповідність небезпечна і для ревʼю, і для реальних користувачів.
Помилка № 3: ігнорувати ШІ‑специфіку в Terms.
Якщо в Terms немає жодного слова про те, що відповіді генерує модель і вони можуть бути неточними, користувач цілком може очікувати від вашого застосунку рівня «істини в останній інстанції». Для сервісів рекомендацій (подарунки, подорожі, добір товарів) це ще терпимо, але для медицини, фінансів або правових порад такий пробіл може завершитися дуже погано. Краще прямо й чесно проговорити обмеження та відповідальність.
Помилка № 4: Support‑сторінка без реального контакту або з «мертвою» адресою.
Сторінка /support, яка веде на mailto:hello@example.com, куди ніхто ніколи не заглядає, формально існує, але фактично марна. Користувач не отримує зворотного звʼязку, репорти про баги губляться, а репутація застосунку падає. Платформа також очікує, що ви відповідатимете на скарги та проблеми. Навіть якщо ви маленька команда, важливо хоча б раз на кілька днів переглядати вхідні та реагувати.
Помилка № 5: забувати про дату й версію документів.
Іноді на юридичних сторінках узагалі немає вказівки, коли їх оновлювали востаннє. Для ревʼюера це тривожний знак: незрозуміло, чи відповідають документи поточному стану продукту. Простий блок «Last updated: …» розвʼязує проблему і для вас, і для користувачів. Також він допомагає вести історію змін, якщо з часом ви допрацьовуєте архітектуру і, відповідно, текст Policy/Terms.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ