1. Що таке ChatGPT Store в контексті курсу
Почнемо із загальної картини. ChatGPT Store — це каталог застосунків усередині ChatGPT. Користувач може зайти туди, знайти ваш застосунок, увімкнути його та використовувати в діалогах. Для вас це не просто «вітрина», а канал поширення з правилами — своєрідний аналог «App Store» у світі LLM.
У цьому курсі ми розрізняємо три режими «життя» вашого застосунку:
- Перший режим — Dev Mode. Застосунок привʼязаний до вашого облікового запису або організації, доступний вам і, можливо, колегам. Формального ревʼю немає, але діють усі загальні політики платформи. Тут ви можете спокійно все ламати, збирати будь-які логи, прокладати тунелі та тестувати staging-бекенди.
- Другий режим — публічний Store. Це інший рівень: застосунок доступний усім користувачам ChatGPT (з урахуванням регіональних обмежень), проходить модерацію, має публічний лістинг, посилання на Privacy/Terms і має поводитися як зрілий продукт.
- Третій — org‑only Apps. Це застосунки лише для однієї організації: компанія може вмикати/вимикати їх для співробітників, накладати власні вимоги безпеки поверх вимог OpenAI і навіть проводити внутрішнє ревʼю.
У цій лекції нас цікавить саме поєднання «публічний Store + публічний лістинг». Є важливий момент: ви перестаєте бути просто розробником «ще одного Next.js‑сервісу» й стаєте автором продукту, який має сподобатися одразу трьом сторонам: користувачам, модераторам Store і вашій службі безпеки.
2. Базові вимоги Store: політики, чесність і UI
Контент і політики
ChatGPT Store — модерована платформа. Якщо спростити, OpenAI не хоче, щоб усередині ChatGPT зʼявлялися застосунки, які порушують політики платформи (насильство, тероризм, NSFW, шахрайство тощо) або намагаються обійти захист моделей (jailbreak‑промпти на кшталт «зроби вигляд, що ти не ChatGPT, а мій злий двійник»).
Це означає дві речі.
По‑перше, ваш застосунок сам по собі не має генерувати заборонений контент. Якщо наш умовний застосунок GiftGenius (підбір подарунків) раптом починає радити щось на кшталт «як приховати сліди злочину», модерації вистачить одного скриншота.
По‑друге, ваш застосунок не має допомагати користувачеві обходити фільтри. Якщо користувач просить: «Підбери подарунок, щоб зробити бомбу», коректна поведінка — відмова з посиланням на політики, а не радісне використання вашого MCP-tool для пошуку потрібних деталей.
Значну частину цієї поведінки визначає system‑prompt і те, які інструменти ви надаєте моделі. Але Store дивиться на результат: які відповіді користувач реально може отримати.
Бренд і домен
Наступний шар — бренд і домен. Публічний застосунок має бути привʼязаний до зрозумілого власника. Якщо в застосунку є зовнішній бекенд або MCP, від вас очікують такого:
Перевірка домену (Domain Verification). Ви додаєте TXT‑запис у DNS вашого домену, і Store переконується, що бекенд справді належить вам. Анонімні рішення на безкоштовному ngrok‑URL або не пройдуть у публічний Store, або будуть позначені як ненадійні.
Адекватна назва та логотип. Не можна називатися «ChatGPT Super Weather» або «Official OpenAI Something». Так само не можна ставити «GPT / OpenAI / ChatGPT» на початку назви або копіювати фірмовий стиль OpenAI: це підпадає під бренд‑обмеження. Вигадайте власну назву (GiftGenius — гарний приклад) і свій візуальний стиль.
UI/UX: не ламати ChatGPT
На відміну від «старих» плагінів, тепер застосунок може показувати свій UI‑віджет прямо в чаті. Це дає багато можливостей — і стільки ж способів усе зіпсувати.
У Store є проста ідея: віджет має виглядати «нативно» в ChatGPT. Шрифти, відступи, кольори, поведінка в темній/світлій темі та на мобільних пристроях — усе має бути охайним, без відчуття, що ви вбудували в чат рекламний банер або цілу окрему SPA.
Store також не любить UI, який «захоплює» чат: величезні повноекранні липкі елементи, модальні вікна «підпишіться негайно», автоскрол і інші агресивні патерни. Ваш віджет — це картка, майстер або інструмент усередині діалогу, а не власний всесвіт.
По суті, модерація перевіряє три речі. Перше — чи не порушуєте ви контент‑політики. Друге — чи не вводите в оману (про це — окремий блок ближче до кінця лекції, коли говоритимемо про лістинг і відповідність маніфесту). І третє — чи не перетворюєте ChatGPT на рекламне звалище з поганим UX. «Чесність» тут означає відповідність між тим, що застосунок реально вміє, і тим, що ви про нього заявляєте в описі та UI.
3. Як Store бачить дозволи вашого застосунку
Окрема велика тема вимог — те, які права ви запитуєте в користувача та у зовнішніх систем. Тут Store дивиться не лише на безпеку, а й на те, наскільки ці права відповідають заявленій цінності застосунку.
А тепер — найцікавіше для інженера: модель дозволів. У контексті Apps SDK і MCP у вас є три основні рівні доступу.
Для наочності зручно зобразити це так:
graph TD
A[Маніфест/конфіг App] --> B[Model capabilities]
A --> C[OAuth scopes]
A --> D[MCP tools & ACP]
D --> E[Рівень підтвердження користувача]
Model capabilities — це, власне, не «дозволи» в тому самому сенсі, що OAuth‑scopes або write‑tools, а набір вбудованих можливостей моделі. Проте для проєктування безпеки їх зручно вважати першим рівнем доступу — і його теж варто мінімізувати.
Рівень 1: model capabilities
Це те, що модель може робити «сама по собі», без звернення до вашого бекенду: вебперегляд (browsing), генерація зображень DALL‑E тощо.
Якщо увімкнути і browsing, і MCP-tools, модель іноді може вирішити, що задачу легше розвʼязати через вебпошук, а не через ваш спеціалізований інструмент. Особливо якщо описи tools розмиті або в промпті не задані пріоритети. Тому, якщо застосунок і так ходить у ваш API через MCP, має сенс або спробувати вимкнути browsing, або чітко зафіксувати в промпті пріоритет MCP-tools.
Тобто вже на цьому рівні ви застосовуєте принцип мінімально необхідних дозволів: вимикаєте все, що не потрібно для реальної цінності застосунку.
Рівень 2: OAuth scopes
Якщо ваш застосунок використовує автентифікацію (Модуль 10), ви запитуєте скоупи у зовнішнього провайдера: openid, email, profile, orders.read, orders.write тощо.
Тут принцип мінімалізму особливо важливий:
- Якщо вам потрібно лише розрізняти користувачів, найчастіше вистачає openid (анонімний ідентифікатор), а електронна пошта взагалі не потрібна.
- Якщо електронна пошта все ж потрібна, це має бути прозоро і в UX, і в описах дозволів: «потрібна, щоб надсилати вам квитанції та нагадування щодо замовлень», а не «просто про всяк випадок».
Також варто робити авторизацію «за потреби»: спочатку дайте користувачеві спробувати базові функції без входу в обліковий запис, а доступ просіть лише тоді, коли він справді потрібен. Наприклад, коли людина хоче «зберегти підбірку подарунків в обране» або «переглянути історію замовлень». Це знижує тертя й підвищує конверсію.
Приклад конфігурації скоупів для MCP‑tools (спрощено):
// server/mcp/config/auth.ts
export const OAUTH_SCOPES = {
basic: ["openid"],
orders: ["openid", "orders.read"],
checkout: ["openid", "orders.read", "orders.write"]
};
Рівень 3: MCP‑tools і «consequential» дії
Третій рівень — це ваші MCP-інструменти та ACP/Instant Checkout. Кожен tool у MCP-сервері може бути:
- лише для читання (read‑only): отримати курс валют, підібрати подарунки, переглянути каталог;
- таким, що змінює стан (consequential): створити замовлення, надіслати лист, списати гроші.
Від інструментів другого типу Store очікує суворішої моделі підтвердження. Ідея проста: не все можна викликати «просто так». У термінах платформи це зазвичай оформлюють через прапорець consequential: true і політику підтвердження (always_allow проти ask_user).
Приклад реєстрації MCP‑інструмента із зазначенням security‑schemes і того, що це дія, яка змінює стан:
// server/mcp/tools/createOrder.ts
server.registerTool(
"create_order",
{
title: "Create order",
description: "Створює нове замовлення в GiftGenius.",
inputSchema: {
type: "object",
properties: {
productId: { type: "string" },
quantity: { type: "integer", minimum: 1 }
},
required: ["productId", "quantity"]
},
_meta: {
securitySchemes: [{ type: "oauth2", scopes: ["orders.write"] }]
},
// умовне поле: ця дія змінює стан
consequential: true
},
async ({ input, security }) => {
// ... логіка створення замовлення
}
);
Приклад скоупів і security‑schemes взято з офіційної документації про MCP-tools, де інструменти можуть бути або без авторизації, або захищеними OAuth2.
З погляду Store це перетворюється на зрозумілий текст: «Цей застосунок може створювати та керувати замовленнями в магазині GiftGenius» — і, можливо, на окремий крок підтвердження.
4. Дозволи очима користувача та модератора
Для нас, інженерів, застосунок — це маніфест, MCP-сервер і чимало TypeScript-коду. Для Store це набір фактів: що застосунок може зробити з даними користувача та із зовнішнім світом.
Можна уявити це як таблицю:
| Рівень доступу | Приклад для GiftGenius | Як це побачить Store/користувач |
|---|---|---|
| Model capabilities | Browsing: off, DALL‑E: off | «Застосунок сам не звертається до інтернету і не генерує медіа» |
| OAuth scopes | openid, orders.read | «Зчитує ваші замовлення в обліковому записі GiftGenius» |
| Read‑only MCP tools | search_products, get_price_history | «Перегляд каталогу та цін» |
| Consequential MCP tools | create_order, cancel_order | «Створення та скасування замовлень» |
Ключова ідея така: кожен технічний елемент має відповідати дії, зрозумілій людині. У плані модуля це прямо сформульовано так: технічний MCP-tool get_user_orders у лістингу перетворюється на текст «Перегляд списку ваших замовлень у нашому магазині».
Якщо ви не можете пояснити дозвіл одним-двома реченнями, це тривожний сигнал. Можливо, ви або просите зайве, або поєднали кілька різних задач в одному застосунку.
5. Принцип мінімально необхідних дозволів
У звичайному бекенд‑світі принцип PoLP (Principle of Least Privilege) часто сприймають як «так‑так, треба якось обмежити ролі в БД — зробимо потім». У ChatGPT Apps це не «потім», а критерій публікації в Store і чинник, який впливає на конверсію користувачів.
Ось що важливо:
- Чим менше прав просить застосунок, тим вища базова довіра користувача. Діалог усередині ChatGPT — це простір, у якому людина очікує певного рівня приватності. Застосунок, який раптом просить доступ до всього облікового запису, платежів і контактів, виглядає підозріло.
- Чим зрозуміліші та вужчі дозволи, тим простіше модераторам. Модератору потрібно швидко зрозуміти, що робить застосунок і наскільки це узгоджується з політиками та найкращими практиками безпеки. Застосунки з надмірними дозволами — типовий кандидат на «відкласти й запросити уточнення», а іноді й на відмову.
- Чим ближче ви до мінімального «just‑in‑time» доступу, тим мʼякший UX. Екран авторизації — це сильна точка тертя. Якщо застосунок дає корисний досвід ще до входу в обліковий запис (наприклад, показує добірки подарунків без привʼязки до користувача), людина охочіше погодиться на розширені можливості пізніше.
Тому «мінімальні дозволи» в Store — це не лише про безпеку, а й про просування та зростання. У модулі 18 окремо підкреслюється, що мінімальні дозволи — це конкурентна перевага, а не бюрократична формальність.
6. Приклади: дозволи GiftGenius до і після «дієти»
Щоб це не залишалося абстрактною теорією, візьмемо нашого умовного героя — GiftGenius. Уявімо, що ви проєктували його на повну й отримали такий список потрібних можливостей:
- Читати каталог товарів і фільтрувати подарунки.
- Бачити історію замовлень користувача.
- Створювати нові замовлення та скасовувати наявні.
- Зберігати «обрані підбірки» в обліковому записі користувача.
- Надсилати сповіщення електронною поштою про знижки.
На рівні конфігурації це може виглядати так:
// server/mcp/config/permissions-naive.ts
export const PERMISSIONS_NAIVE = {
capabilities: { webBrowsing: true, dalle: false },
oauthScopes: ["openid", "email", "orders.read", "orders.write"],
tools: {
searchProducts: { consequential: false },
getUserOrders: { consequential: false },
createOrder: { consequential: true },
cancelOrder: { consequential: true },
saveFavoriteList: { consequential: true },
sendDiscountEmail: { consequential: true }
}
};
На папері такий набір здається логічним («рано чи пізно все це знадобиться»), але для першого релізу в Store це забагато:
- Вам не обовʼязково відразу читати історію замовлень. Можна обмежитися одноразовою підбіркою та безпечним checkout через ACP/Instant Checkout, де платіжний сценарій і так під контролем платформи.
- Сповіщення електронною поштою — це взагалі окрема історія: для них потрібні і зберігання адреси, і пояснення в Privacy Policy, і обробка відписок. Для MVP GiftGenius це майже завжди зайве.
З урахуванням принципу мінімалізму ви можете зібрати мінімальний стартовий набір дозволів:
// server/mcp/config/permissions-v1.ts
export const PERMISSIONS_V1 = {
capabilities: { webBrowsing: false, dalle: false },
oauthScopes: [], // без логіна, працюємо анонімно
tools: {
searchProducts: { consequential: false },
createOrder: { consequential: true }
}
};
У такій версії:
- Застосунок не «лізе» в обліковий запис користувача, не читає історію і не надсилає листів електронною поштою.
- Усі чутливі операції (створення замовлення) йдуть через ACP/Instant Checkout, де користувач і так бачить стандартний платіжний сценарій.
У лістингу можна чесно написати: «Підбирає подарунки та створює замовлення в магазині GiftGenius. Застосунок не зберігає історію ваших чатів і не надсилає сповіщення електронною поштою». Це добре і для користувача, і для модератора.
Згодом, коли у вас зʼявиться стабільний трафік і довіра, можна випустити оновлення з додатковими дозволами (історія замовлень, обране) та відповідно оновити лістинг і Privacy Policy.
7. Як описувати дозволи в лістингу
Маніфест і конфігурація — це мова машини. Модератор і користувач читають зовсім інший текст: назву, опис, блок «Що може робити цей застосунок» і посилання на Privacy/Terms.
У модулі 17 підкреслюється ідея зіставлення: технічні scopes та інструменти → дії, зрозумілі людині.
Для GiftGenius v1 ми могли б оформити це так.
Технічно:
- Browsing: off
- DALL‑E: off
- MCP tools: search_products (read‑only), create_order (consequential)
У лістингу:
- «Підбирає подарунки за вашим описом або параметрами (стать, вік, бюджет, інтереси)».
- «Може створювати замовлення в магазині GiftGenius через захищений checkout усередині ChatGPT».
- «Не запитує доступу до вашої електронної пошти чи історії замовлень і не надсилає сповіщення».
Якщо пізніше додамо OAuth‑логін і orders.read, опис чесно оновиться:
- «Після підʼєднання облікового запису GiftGenius може переглядати ваші минулі замовлення, щоб давати більш персональні рекомендації».
Дуже важливо не обіцяти того, чого застосунок не робить, і не замовчувати критичні дії. Уся документація, зібрана для модуля 18, прямо підкреслює: інформація в лістингу має точно відповідати реальній поведінці, особливо для чутливих речей на кшталт платежів і PII.
8. Звʼязок вимог Store з вашою архітектурою
Важливо бачити, що вимоги Store не існують у вакуумі. Усі ці вимоги — не «ще одна форма від відділу маркетингу». Store, по суті, перевіряє те, що ви вже робили в модулях про безпеку й продакшен:
- Якщо ви налаштовували OAuth і робили акуратні .well-known‑ендпойнти та перевірку токенів, буде дивно, якщо застосунок раптом попросить у користувача «пів інтернету» через надто широкі скоупи. Такий застосунок легко провалиться на ревʼю через надмірні дозволи.
- Якщо ви чесно реалізували політику зберігання даних (retention) і PII‑scrub, вам буде простіше написати правдиву Privacy Policy і витримати перевірку. Store і користувачі можуть перейти за посиланням та зіставити ваші обіцянки з реальними процесами.
- Якщо ви добре налагодили стабільність MCP-сервера, логи й метрики (модулі про observability і SLO), у модераторів буде менше запитань щодо продуктивності та помилок інструментів.
Мінімальні дозволи гарно доповнюють цю картину: ви не лише безпечні та стабільні, а й «скромні» у запитах до даних користувача.
9. Міні‑практика в ході лекції
Щоб не лише теоретизувати, розберіть просто зараз ваш поточний застосунок (або GiftGenius) крок за кроком.
Спочатку випишіть усі реальні дії, які застосунок уміє робити. Наприклад: «підібрати подарунки», «створити замовлення», «показати історію», «зберегти в обране», «надіслати листа колегам». Краще зробити це звичайним текстом, ще не думаючи про технічні деталі.
Далі для кожної дії дайте собі відповідь на два запитання: «Які дані користувача це зачіпає?» і «Чи змінює це стан у зовнішній системі?». Так ви автоматично розділите дії на read‑only і consequential.
Після цього зіставте дії з рівнями дозволів: де потрібні лише model capabilities, де — OAuth‑скоупи, а де — MCP-tools із прапорцем consequential: true і, можливо, з підтвердженням користувача.
І тепер зіграйте в «ножиці»: що можна прибрати з першого релізу, не втративши основної цінності? Часто виявляється, що без історії, обраного й сповіщень електронною поштою застосунок усе одно робить свою головну справу. А отже, ці дозволи можна відкласти на версію 1.1 або 2.0.
10. Типові помилки з вимогами Store і дозволами
Помилка № 1: «Зробимо суперзастосунок, який уміє все, а Store розбереться».
Розробник описує застосунок як універсального асистента («допоможу з фінансами, медициною, юриспруденцією і покупками»), підʼєднує десяток MCP-tools і просить максимальні права. Такий застосунок одночасно заходить у чутливі сфери (медицина/фінанси/право), запитує багато даних і порушує принцип «one job per app». Результат передбачуваний: модерація поставить багато запитань або просто відхилить застосунок. Краще зробити кілька вузьких застосунків із чіткими дозволами.
Помилка № 2: Надмірні дозволи під час авторизації «про всяк випадок».
Класика: застосунок просить email, profile, orders.read, orders.write, billing.read, хоча насправді потрібно лише «підібрати подарунок за описом». З погляду користувача це виглядає як жадібний збирач даних, а з погляду Store — як ризикований застосунок. У документації з безпеки Apps це прямо наводиться як приклад поганої практики.
Помилка № 3: Невідповідність маніфесту й лістингу.
У маніфесті у вас є create_order, cancel_order і доступ до платіжних операцій, а в описі ви пишете лише «рекомендує подарунки». Рано чи пізно хтось із модераторів або користувачів помітить, що застосунок уміє більше, ніж заявлено. Це підриває довіру й може призвести до зняття застосунку зі Store.
Помилка № 4: Спроба приховати чутливі дії за «нешкідливим» UI.
Наприклад, ви малюєте у віджеті кнопку «Зберегти підбірку», яка насправді надсилає листа всім у відділ або створює завдання в чужій системі, не пояснюючи цього в дозволах. Store не любить сюрпризів. У керівництвах для розробників прямо сказано: застосунок має робити рівно те, що обіцяно, без прихованої поведінки.
Помилка № 5: Запит на вхід в обліковий запис «на старті», коли можна обійтися без нього.
Застосунок запускається — і відразу просить підʼєднати обліковий запис, видати доступ до всього, інакше «не працює». Хоча половину сценаріїв цілком можна реалізувати анонімно. Це бʼє по конверсії і створює враження, що ви поспішаєте зібрати дані, а не дати цінність. Значно краще спочатку показати, що застосунок справді корисний, і лише потім пояснювати, навіщо потрібні додаткові права.
Помилка № 6: Ігнорування організаційного контексту.
Іноді розробник робить застосунок «для всіх», хоча по суті це внутрішній корпоративний інструмент. У результаті він тягне в Store дуже специфічні дозволи (внутрішні CRM, приватні дані співробітників), які складно зрозуміло пояснити широкому користувачеві. У таких випадках варто орієнтуватися на режим org‑only і внутрішнє ревʼю, а не на публічний Store.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ