Розробка фотобанку / стокового сервісу
Фотобанк — це медіабібліотека з монетизацією. Технічно це перетин трьох доменів: управління великими бінарними об'єктами, пошук за метаданими та візуальним вмістом, ліцензійні транзакції. Кожен з них нетривіальний окремо, разом — вимагають продуманої архітектури з самого початку.
Типи стоків та їх технічні відмінності
Перш ніж проектувати систему, важливо розуміти модель:
Microstock (iStock, Shutterstock-модель) — величезна бібліотека, низька ціна, підписка або кредити. Ключова метрика — пошук та конверсія. Потрібен потужний пошук з машинним зором.
Macrostock / Editorial — менше контенту, високі ціни, ліцензування за запитом. Упор на управління правами та документацію походження.
Нішевий сток — фото певної тематики (архітектура, медицина, їжа). Простіше в модерації, легше SEO.
Власний фотоархів компанії — не публічний сток, а внутрішній DAM (Digital Asset Management). Інші вимоги: інтеграція з CMS, контроль доступу за ролями.
Завантаження та зберігання файлів
Мінімальні вимоги до завантажених файлів на типовому стоці: JPEG/TIFF/PNG, мінімум 4 Мп, до 200 МБ. Відео — MP4/MOV до 4K, до 2 ГБ. Це означає, що завантаження безпосередньо на сервер програми виключено.
Схема multipart upload через S3:
Клієнт → presigned URL (S3) → завантаження безпосередньо в S3
S3 Event → SQS → Worker: генерація превю, валідація, метадані
Worker → БД: запис asset з status=processing → status=ready
Зберігання: AWS S3 або будь-який S3-сумісний (MinIO для self-hosted). Структура бакетів:
-
originals/— оригінали, приватний доступ, тільки за підписаними URL -
previews/— водяний знак, публічний CDN -
thumbnails/— кілька розмірів (400px, 800px, 1600px), генеруються при завантаженні
Для генерації превю: ImageMagick або libvips (у 4–8 разів швидше). Водяний знак накладається при генерації превю, не при роздачі — інакше не можна змінювати брендинг без перегенерації.
Метаданні та пошук
Метадані медіа-файлів живуть у двох місцях: EXIF/IPTC всередині файлу та в базі даних. При завантаженні розбираємо IPTC-теги (ExifTool), переносимо в БД, даємо автору доповнити вручну.
Структура метаданих:
assets (id, uuid, author_id, title, description, status, license_type, uploaded_at)
asset_tags (asset_id, tag_id)
asset_categories (asset_id, category_id)
asset_metadata (asset_id, key, value) -- EXIF, IPTC, користувацькі поля
Повнотекстовий пошук: Elasticsearch з російським аналізатором. Індексуємо: title, description, tags, категорії, ім'я автора, IPTC-ключові слова. Буст за полями: теги > title > description.
Візуальний пошук (пошук за подібними зображеннями): генеруємо perceptual hash (pHash) при завантаженні. Пошук подібних — hamming distance за хешами. Для просунутої реалізації — CLIP-вбудовування через OpenAI API або локальна модель, зберігання у векторній БД (pgvector або Qdrant).
Пошук за кольором: витягуємо домінантні кольори через k-means кластеризацію (Pillow / ColorThief), зберігаємо HEX-палітру, індексуємо в Elasticsearch як keyword-поле з boost.
Ліцензування та транзакції
Ліцензії — ядро бізнес-логіки стоку. Мінімальний набір типів:
| Тип | Описання | Технічна реалізація |
|---|---|---|
| RF (Royalty Free) | Одноразова оплата, багаторазове використання | Проста покупка, запис в licenses |
| RM (Rights Managed) | Оплата за кожне використання, залежить від тиражу | Калькулятор при покупці, детальний запис використання |
| Editorial | Тільки для новин/редакцій, не для реклами | Прапорець в asset + перевірка при оформленні |
| Extended | Тиражи без обмежень, перепродаж | Окремий прайс, ручна модерація |
Видача файлу після оплати — одноразовий підписаний URL з TTL 15–60 хвилин. Не пряма посилання на S3. При кожній видачі — запис у журнал з user_id, asset_id, timestamp, IP.
Система підписок та кредитів
Дві моделі монетизації часто існують паралельно:
Підписка: X завантажень на місяць, певні дозволи, rollover або скидання. Реалізується через Stripe Subscriptions + webhooks. При завантаженні перевіряємо subscription.downloads_remaining, декрементуємо атомарно (Redis DECR).
Кредити: користувач купує пакет кредитів, витрачає при завантаженні. Різні файли коштують різну кількість кредитів (залежить від розділення, типу ліцензії). Транзакції у окремій таблиці з балансом — ніколи не зберігати баланс як мутуючу поле без історії.
Завантажувач для авторів
Авторський кабінет — окрема частина системи. Ключові вимоги:
- Batch upload: завантаження 50–200 файлів одночасно з прогрес-барами на кожен файл
- Bulk metadata editing: виділити кілька файлів, застосувати теги/категорії до всіх
- Модерація pipeline: завантажено → на перевірці → одобрено/відхилено з коментарем
- Статистика автора: перегляди, завантаження, дохід, топ-файли
Для batch upload на фронті: <input multiple> + chunked upload через tus protocol (resumable uploads). Клієнтська бібліотека — tus-js-client. На сервері — tusd або користувацька реалізація на Laravel.
Модерація контенту
Автоматична пре-модерація прискорює ручну перевірку:
- NSFW-детектор: Google Cloud Vision SafeSearch або відкрита модель (NudeNet) — фільтруємо явний контент до ручної перевірки
- Дублі: pHash-порівняння з уже схваленими файлами, поріг hamming distance ≤ 10
- Технічні проблеми: перевірка мінімальної розділення, шуму, різкості через ImageMagick identify
Після автопроверки — черга для модератора з пріоритизацією (нові автори перевіряються суворіше).
SEO та індексація
Сторінки фотографій — основний SEO-трафік. Кожна сторінка асету:
- URL:
/photos/{category}/{slug}-{id}— читаємий, без хеша - Title:
{title} — стокове фото #{id}(унікальний) - Structured data:
ImageObjectSchema.org зcontentUrl,author,license,keywords - Пов'язані фото: внутрішні посилання за тегами та категоріями
Для каталогів з мільйонами файлів — XML sitemap розбивається на індекс + окремі файли за категоріями, оновлюється інкрементально.
Продуктивність
- Сторінки каталогу кешуються на рівні CDN (Cloudflare) з
Cache-Control: stale-while-revalidate - Превю роздаються через CDN з immutable кешем (ім'я файлу включає хеш контенту)
- Пошук — Elasticsearch, ніякого SQL для пошукових запитів
- Lazy loading превю: Intersection Observer API, placeholder — домінантний колір з метаданих
Строки
- MVP (завантаження, пошук за тегами, покупка RF-ліцензії, Stripe): 8–12 тижнів
- Повноцінний сток (підписки, візуальний пошук, авторський кабінет з модерацією, SEO-шар): 20–30 тижнів
- Інтеграція CLIP-пошуку або детектора дублів додає 2–4 тижні до будь-якого етапу
Складність фотобанку часто недооцінюється, коли його сприймають як «каталог з файлами». Різниця стає очевидною на етапі ліцензування та масштабування сховища.







