Зустрічі та розробка:
- У тебе буде 3 консультації з ментором, де ви разом розберете важливі частини проекту.
- Ментор допоможе визначити комфортний дедлайн для завершення роботи.
- Основний функціонал ви напишете разом на консультаціях.
Здача проекту:
- Завантаж проект у Git-репозиторій
- Надішли посилання через форму
Успіхів у роботі 💪
Наше завдання — створити сервіс для перегляду та зберігання зображень у вигляді веб-додатку. Суть проста: користувач заходить на сайт, завантажує фотки чи картинки, а натомість отримує прямі посилання на них. Ці посилання можна використовувати де завгодно — у соцмережах, блогах або просто надіслати друзям.
- Бекенд пишемо на Python — він чудово підходить для таких завдань.
- Для швидкої роздачі зображень використовуємо Nginx — він просто створений для цього.
- Все запакуємо в Docker-контейнери, щоб проект легко запускався на будь-якому комп'ютері.
- Docker Compose допоможе керувати всіма компонентами як єдиним цілим.
Наш сервіс — це не просто сховище зображень. Це місце, де користувачі можуть:
- Завантажувати фотки в популярних форматах (.jpg, .png, .gif).
- Бути впевненими, що їхні зображення надійно збережені.
- Отримувати зручні прямі посилання на завантажені зображення.
Ну а ми, розробники, будемо стежити за всім процесом через систему логів, щоб знати, що робити, якщо щось піде не так.
А для навчання цей проект — чудовий шанс покращити свої навички в Python-розробці, налаштуванні веб-серверів, роботі з Docker та взаємодії різних компонентів системи один з одним.
- Розробити Python-бекенд для обробки запитів, завантаження зображень та логування дій користувачів.
- Налаштувати Nginx для роздачі завантажених зображень.
- Запакувати проект у Docker-контейнери, з використанням Docker Compose для керування.
- Налаштувати Docker Volumes для довготривалого зберігання зображень та логів.
- Реалізувати інтерфейс для взаємодії з користувачем (завантаження зображень та доступ до файлів).
- Макет сайту - https://www.figma.com/design/ivhGgfIBMDsA2xF3qospb6/image-hosting?node-id=0-1&p=f
- HTML Template - https://github.com/MagicCodeGit/image-hosting.git
1. Головна сторінка
- Маршрут:
/ - Функціональність:
- Зустрічає користувача вітальним повідомленням та розповідає про сервіс.
- Містить посилання на основні маршрути:
- Сторінка завантаження зображень (
/upload). - Каталог завантажених зображень (
/images/).
2. Завантаження зображень
- Маршрут:
/upload - Метод:
POST - Функціональність:
- Приймає файл зображення від користувача через HTTP-запит.
- Підтримувані формати:
.jpg,.png,.gif. - Обмеження розміру файлу: до 5 МБ.
- Генерує унікальне ім'я для кожного завантажуваного зображення.
- Зберігає зображення в папку
/imagesна сервері. - Повертає користувачу унікальний ідентифікатор файлу та посилання на зображення.
3. Доступ до завантажених зображень
- Маршрут:
/images/<ім'я_файлу> - Функціональність:
- Всі завантажені зображення мають бути доступні для перегляду та завантаження за прямими посиланнями.
- Nginx обслуговує цей маршрут, роздаючи файли з папки
/images.
4. Логування дій
- Функціональність:
- Записує кожну дію користувача в лог-файл
app.log.
- Записує кожну дію користувача в лог-файл
- Формат запису:
[Дата/час] Дія: повідомлення
Приклади записів:
[2025-01-24 14:00:00] Успіх: зображення img1.jpg завантажено.
[2025-01-24 14:01:00] Помилка: непідтримуваний формат файлу (user_file.txt).
- Логи потрібно зберігати в окремому томі Docker.
1. Завантаження зображення
- Користувач переходить на маршрут
/upload. - Завантажує файл через HTTP-запит (наприклад, за допомогою форми або програми
curl). - Бекенд перевіряє формат та розмір файлу.
- Якщо файл успішно завантажено:
- Він зберігається в папці
/images. - Користувачу повертається повідомлення з унікальним посиланням на файл (наприклад,
/images/img1.jpg).
- Він зберігається в папці
- Якщо файл не відповідає вимогам:
- Користувачу повертається повідомлення про помилку (наприклад, "Непідтримуваний формат файлу").
2. Перегляд завантажених зображень
- Користувач переходить за посиланням
/images/<ім'я_файлу>. - Nginx повертає запитане зображення для перегляду або завантаження.
- Багатозадачність: сервер легко справляється з 10 користувачами, які завантажують картинки одночасно. Жодних гальмувань та зависань!
- Швидкість завантаження: час обробки завантаження одного зображення (включаючи збереження та генерацію імені) не повинен перевищувати 1 секунди.
- Миттєвий перегляд: Nginx роздає картинки зі швидкістю світла (ну гаразд, менше 100 мілісекунд). Відкрили посилання — відразу побачили картинку, жодного "завантажується...". Коротше кажучи, все має працювати швидко та без затримок! ⚡
- Розмір файлів: максимальний розмір завантажуваного зображення — 5 МБ.
- Підтримувані формати: тільки
.jpg,.pngта.gif. Спроба завантажити непідтримуваний формат має повертати повідомлення про помилку. - Обсяг зберігання: сховище зображень не повинно перевищувати доступний простір тому Docker (за замовчуванням обмежень на обсяг не вводиться, але передбачається розумне використання дискового простору).
- Система має коректно обробляти некоректні запити:
- Завантажені файли, що не відповідають формату або розміру, мають викликати повернення помилки (400 Bad Request).
- У разі збою сервер має автоматично перезапускатися (мається на увазі використання Docker для автоматичного відновлення).
- Проект орієнтований на навчальні цілі, але має бути спроектований таким чином, щоб за необхідності:
- Збільшити кількість бекенд-серверів для обробки завантажень.
- Розширити сховище зображень.
- Додати нові маршрути або функціональність (наприклад, базу даних).
- Мова програмування: Python (версія 3.12 або вище).
- Сервер для статичних файлів: Nginx.
- Контейнеризація: Docker та Docker Compose.
- Бібліотеки Python:
- Обов'язково:
Pillow(для роботи з зображеннями, якщо потрібно). - Додатково: тільки стандартна бібліотека для обробки запитів (наприклад,
http.server).
- Усі сервіси (бекенд та Nginx) потрібно запакувати в окремі Docker-контейнери.
- Керування контейнерами потрібно організувати за допомогою Docker Compose.
- Мають бути використані два томи:
images: для зберігання завантажених зображень.logs: для збереження логів.
Щоб запустити проект достатньо однієї команди:
docker compose up --build- Усі залежності мають бути включені в
Dockerfileтаcompose.yaml.
Звісно, нам потрібно захистити сервіс від усіляких неприємностей! Що для цього робимо? Перевіряємо все, що завантажують:
- Приймаємо тільки картинки (jpg, png, gif) — жодних шкідливих файлів
- Стежимо за розміром - великі файли можуть перевантажити сервер
- Якщо хтось намагається завантажити щось дивне — відразу кажемо "ні" і пояснюємо причину
Захищаємо доступ до файлів:
- Картинки доступні тільки за спеціальними посиланнями виду
/images/назва_файлу - Весь доступ до файлів йде через Nginx — він у нас як надійний охоронець
- Жодних обхідних шляхів - безпека понад усе! 🛡️
- Зображення: зберігаються в папці
/images, монтованій як volume. - Логи: зберігаються в папці
/logs, монтованій як volume. - Довготривалість даних: том Docker зберігає всі файли між перезапусками контейнерів.
- Логи мають бути читабельними та інформативними.
- Формат логів:
[Дата/час] Дія: повідомлення
- Логи зберігаються в текстовий файл
app.logв папці/logs.
- Додаток має бути доступний:
- Бекенд за адресою:
http://localhost:8000. - Статичні зображення через Nginx за адресою:
http://localhost:8080/images/<ім'я_файлу>.
Ми пишемо код не тільки для комп'ютера, але й для людей! Тому:
Код має бути зрозумілим:
- Використовуємо змістовні імена змінних та функцій
- Додаємо коментарі до складних місць
- Дотримуємось єдиного стилю оформлення
API робимо гнучким:
- Кожен маршрут (/upload, /images та інші) детально документуємо
- Залишаємо можливість легко додати нові функції
- Пишемо код так, щоб його можна було розширювати, а не переписувати
Загалом, робимо так, щоб навіть через півроку будь-який розробник міг розібратися і щось додати! 👨💻
Система складається з двох основних компонентів:
- Python-бекенд:
- Відповідає за обробку HTTP-запитів, завантаження зображень, валідацію даних та логування.
- Виконує бізнес-логіку додатку, пов'язану з керуванням завантаженими файлами.
- Працює всередині Docker-контейнера, слухаючи запити на порту
8000.
- Nginx-сервер:
- Роздає статичні файли та завантажені зображення за маршрутом
/images/. - Проксує запити на Python-бекенд для інших маршрутів.
- Працює в окремому Docker-контейнері, слухаючи запити на порту
80.
Компоненти взаємодіють через локальну мережу, створену за допомогою Docker Compose.
Коли користувач завантажує картинку:
- Користувач надсилає файл через
POST /uploadна Python-бекенд. - Бекенд бере всю роботу на себе:
- Перевіряє, чи все гаразд з файлом
- Придумує йому унікальне ім'я
- Зберігає в папку
/imagesчерез Docker volume - Записує в лог, що і коли завантажили
- Віддає користувачу посилання на його картинку
Коли користувач хоче подивитися картинку:
- Запитує картинку через
GET /images/<ім'я_файлу>у Nginx - Nginx шукає файл у папці
/images - Якщо знайшов - віддає картинку користувачу
Хто за що відповідає:
- Python-бекенд — "розумна" частина: перевіряє файли, обробляє завантаження
- Nginx — "швидка" частина: роздає картинки і працює як проксі
Директорії та файли:
project/
├── app.py # Основний Python-бекенд
├── requirements.txt # Залежності Python
├── Dockerfile # Dockerfile для Python-бекенду
├── docker-compose.yml # Конфігурація Docker Compose
├── nginx.conf # Конфігурація Nginx
├── images/ # Папка для зберігання завантажених зображень (volume)
├── logs/ # Папка для логів (volume)
└── static/ # Додаткові статичні файли (CSS/JS, якщо застосовно)
Опис ключових компонентів:
- app.py:
- Реалізує обробку HTTP-запитів:
GET /— головна сторінка.POST /upload— завантаження зображення.
- Виконує:
- Валідацію завантажуваного файлу (формат, розмір).
- Збереження файлу в папку
/images. - Логування дій у файл
app.log.
- nginx.conf:
- Роздає вміст папки
/imagesза маршрутом/images/<ім'я_файлу>. - Проксує запити, не пов'язані зі статикою, на Python-бекенд.
- compose.yaml:
- Визначає два сервіси:
app— Python-бекенд.nginx— Nginx-сервер.
- Створює два томи:
images— для зберігання завантажених зображень.logs— для зберігання логів.
- images/:
- Каталог, у який зберігаються всі завантажені файли.
- Підключається як volume для довготривалого зберігання.
- logs/:
- Каталог, що містить лог-файли (
app.log). - Підключається як volume для збереження даних між перезапусками.
- Порти та маршрути:
- Python-бекенд:
- Зовнішній порт:
8000(для локального налагодження). - Nginx:
- Зовнішній порт:
8080(для користувачів). - Внутрішня мережа Docker зв'язує два контейнери:
- Nginx звертається до Python-бекенду за адресою
http://app:8000.
-
Користувацький запит: Користувач взаємодіє з системою через маршрути:
/— головна сторінка (обробляється бекендом)./upload— завантаження зображення (обробляється бекендом)./images/<ім'я_файлу>— доступ до зображення (обробляється Nginx).
-
Обробка запитів:
- Nginx:
- Роздає статичні файли та завантажені зображення.
- Переадресовує запити на Python-бекенд, якщо маршрут не пов'язаний з інтерфейсом та зображеннями.
- Python-бекенд:
- Приймає і обробляє запити
/та/upload. - Зберігає зображення та записує логи.
- Приймає і обробляє запити
- Nginx:
-
Зберігання даних:
- Зображення:
- зберігаються в volume, підключеному як
/images.
- зберігаються в volume, підключеному як
- Логи:
- зберігаються в volume, підключеному як
/logs.
- зберігаються в volume, підключеному як
- Зображення:
-
Завантаження зображення:
- Користувач надсилає файл на маршрут
/upload. - Python-бекенд:
- Перевіряє файл.
- Зберігає файл в
/images. - Логує дію.
- Користувачу повертається посилання виду
/images/<ім'я_файлу>.
- Користувач надсилає файл на маршрут
-
Доступ до зображення:
- Користувач надсилає запит на
/images/<ім'я_файлу>. - Nginx перевіряє файл у папці
/imagesі повертає його.
- Користувач надсилає запит на
- Мова програмування: Python 3.12 або вище.
- Бібліотеки Python:
- Стандартна бібліотека: для роботи з HTTP-запитами (
http.server), файловою системою (os), логуванням (logging) та JSON. - Pillow: для роботи з зображеннями (за необхідності, якщо знадобиться перевірка або обробка зображень).
- Nginx:
- Має бути налаштований для роздачі зображень з папки
/images. - Має проксувати всі запити, що не стосуються статики, на Python-бекенд.
- Порт для зовнішнього доступу:
8080.
- Docker:
- Усі компоненти додатку мають бути запаковані в контейнери:
- Python-бекенд.
- Nginx-сервер.
- Мають бути використані два Docker Volumes:
images— для зберігання завантажених зображень.logs— для зберігання логів.
- Для керування контейнерами використовується Docker Compose.
- Усі компоненти додатку мають бути запаковані в контейнери:
- Docker Compose:
- Конфігурація має містити:
- Сервіс для Python-бекенду:
- Назва:
app. - Порт:
8000. - Підключення томів для зображень та логів.
- Назва:
- Сервіс для Nginx:
- Назва:
nginx. - Порт:
8080. - Підключення тому для зображень.
- Проксування запитів на Python-бекенд.
- Назва:
- Сервіс для Python-бекенду:
- Конфігурація має містити:
- Зображення:
- зберігаються в локальній папці
/images, підключеній через volume. - кожне зображення має мати унікальне ім'я, що генерується Python-бекендом.
- обмеження:
- Підтримувані формати:
.jpg,.png,.gif. - Максимальний розмір файлу: 5 МБ.
- Підтримувані формати:
- зберігаються в локальній папці
- Логи:
- логи пишуться в файл
app.log, розташований у папці/logs. - лог-файл має бути доступний для читання між перезапусками контейнера.
- логи пишуться в файл
- Взаємодія контейнерів:
- Python-бекенд (
app) та Nginx (nginx) мають бути зв'язані через внутрішню мережу Docker. - Nginx проксує запити до Python-бекенду за адресою
http://app:8000. - Порти:
- Nginx: доступний на порту
8080для користувачів. - Python-бекенд: слухає запити на порту
8000(всередині контейнера).
-
Перевіряємо кожен файл перед завантаженням:
-
"Це точно картинка?" — приймаємо тільки підтримувані формати
-
"Не занадто велика?" — стежимо за розміром файлу
-
Захищаємо доступ до файлів:
-
Жодних "обхідних шляхів" — тільки прямі посилання від бекенду
-
Всі посилання виду
/images/назва_файлу
Тобто спочатку переконуємося, що файл безпечний, а потім даємо до нього доступ тільки через перевірений маршрут.
- Бекенд має обробляти до 10 одночасних запитів.
- Середній час завантаження файлу (включаючи валідацію та збереження) не повинен перевищувати 1 секунди для файлу розміром 5 МБ.
-
Логи мають бути читабельними і містити:
-
Дату та час дії.
-
Тип дії (наприклад, успішне завантаження або помилка).
-
Подробиці дії (наприклад, ім'я завантаженого файлу, причина помилки).
-
Приклад лог-запису:
[2025-01-24 14:00:00] Успіх: зображення img1.jpg завантажено.
Для запуску системи необхідно:
- Встановити Docker та Docker Compose.
- Виконати команду:
docker-compose up --build
- Переконатися, що:
- Бекенд доступний за адресою:
http://localhost:8000. - Статичні файли роздаються за адресою:
http://localhost:8080/images/<ім'я_файлу>.
- Бекенд доступний за адресою:
- Dockerfile:
- Для Python-бекенду з використанням multi-stage build.
- compose.yaml:
- Конфігурація для об'єднання контейнерів.
- nginx.conf:
- Конфігурація Nginx для роздачі зображень та проксування запитів.
- app.py:
- Основний скрипт Python-бекенду.
- requirements.txt:
- Список залежностей Python.
Проект потрібно буде реалізувати поетапно, щоб структурувати процес розробки та забезпечити послідовне виконання всіх вимог. Кожен етап включає ключові завдання та передбачає проміжну перевірку.
-
Встановити необхідні інструменти:
- Docker та Docker Compose.
- Python 3.12 або вище.
-
Налаштувати базову структуру проекту:
project/
├── app.py # Основний Python-бекенд
├── requirements.txt # Залежності Python
├── Dockerfile # Dockerfile для Python-бекенду
├── docker-compose.yml # Конфігурація Docker Compose
├── nginx.conf # Конфігурація Nginx
├── images/ # Папка для зберігання завантажених зображень (volume)
├── logs/ # Папка для логів (volume)
└── static/ # Додаткові статичні файли (CSS/JS, якщо застосовно)
- Створити та протестувати віртуальне оточення Python:
- Переконатися, що всі залежності, вказані в
requirements.txt, встановлюються коректно.
- Переконатися, що всі залежності, вказані в
- Реалізувати базовий HTTP-сервер з маршрутами:
GET /: повертає вітальне повідомлення.POST /upload: обробляє завантаження файлів.
- Додати функціонал:
- Перевірка формату файлу (
.jpg,.png,.gif). - Перевірка розміру файлу (не більше 5 МБ).
- Генерація унікального імені для кожного зображення.
- Збереження зображень у папку
/images. - Повернення посилання на завантажене зображення.
- Перевірка формату файлу (
- Налаштувати логування:
- Створити файл
app.logдля запису дій (успішних та помилкових). - Логи мають містити дату, час, дію та деталі.
- Створити файл
- Протестувати роботу бекенду локально, без Docker.
-
Написати конфігурацію nginx.conf:
- Налаштувати роздачу файлів з папки
/images. - Налаштувати проксування запитів до Python-бекенду для маршрутів, не пов'язаних із зображеннями.
- Налаштувати роздачу файлів з папки
-
Протестувати конфігурацію локально:
- Переконатися, що запити на
/images/<ім'я_файлу>повертають статичні файли. - Переконатися, що запити на інші маршрути перенаправляються на Python-бекенд.
-
Створити Dockerfile для Python-бекенду:
- Реалізувати
multi-stage build, щоб зменшити розмір образу. - Переконатися, що всі залежності встановлюються коректно.
- Реалізувати
-
Налаштувати Docker Compose:
- Створити файл
compose.yaml. - Додати два сервіси:
appдля Python-бекенду.nginxдля Nginx-сервера.
- Налаштувати volume:
imagesдля зберігання завантажених файлів.logsдля запису логів.
- Налаштувати мережу для взаємодії контейнерів.
- Створити файл
-
Протестувати запуск контейнерів:
- Переконатися, що сервіси запускаються командою:
docker compose up --build
- Перевірити доступність бекенду (
http://localhost:8000) та статичних файлів (http://localhost:8080/images/<ім'я_файлу>).
- Перевірити завантаження зображень:
- завантажити зображення різних форматів та розмірів.
- перевірити генерацію унікальних імен та збереження файлів у папці
/images.
- Перевірити обробку помилок:
- спроба завантаження непідтримуваного формату.
- спроба завантаження файлу, що перевищує ліміт розміру.
- Перевірити роздачу файлів через Nginx:
- доступ до завантажених зображень через маршрут
/images/<ім'я_файлу>.
- доступ до завантажених зображень через маршрут
- Перевірити логування:
- переконатися, що всі дії записуються в лог-файл
app.log.
- переконатися, що всі дії записуються в лог-файл
- Написати інструкцію з розгортання проекту:
- Кроки для запуску за допомогою Docker Compose.
- Опис структури проекту та функціональності.
- Додати опис ключових маршрутів API.
- Переконатися, що:
- всі функціональні та нефункціональні вимоги виконано.
- система успішно запускається через Docker Compose.
- всі тести пройдено.
- Упакувати проект:
- архівувати файли проекту.
- підготувати README з коротким описом та інструкцією.
Проект буде оцінюватися в балах: максимум 60 балів.
- Робота маршрутів:
- Головна сторінка (
/) повертає коректне вітальне повідомлення. - Завантаження зображення через маршрут
/uploadпрацює без помилок:- Підтримуються формати
.jpg,.png,.gif. - Перевіряється розмір файлу (до 5 МБ).
- Файли успішно зберігаються з унікальними іменами в папку
/images.
- Підтримуються формати
- Завантажені зображення доступні через маршрути
/images/<ім'я_файлу>.
- Логування:
- Всі дії (успішні завантаження, помилки) записуються в лог-файл
app.logу папці/logs. - Формат логів відповідає вимогам:
[Дата/час] Дія: повідомлення - Всі дії (успішні завантаження, помилки) записуються в лог-файл
- Робота Docker-контейнерів:
Одна команда — і все готово до роботи:
docker compose up --build
- Сервіси працюють незалежно:
- Python-бекенд у своєму контейнері - займається логікою
- Nginx у своєму - роздає файли
-
Сховище даних:
- Завантажені зображення зберігаються в volume
images. - Логи зберігаються в volume
logs.
- Завантажені зображення зберігаються в volume
-
Мережа:
- Nginx коректно проксує запити на Python-бекенд.
- Запити до статичних файлів (
/images/<ім'я_файлу>) обробляються Nginx.
-
Обробка запитів:
- завантаження одного зображення (включаючи перевірку, збереження та генерацію імені) займає не більше 1 секунди.
- система коректно обробляє до 10 одночасних запитів.
-
Роздача файлів:
- Nginx повертає зображення без затримок (час відповіді не перевищує 100 мс для локальних запитів).
-
Завантаження зображень:
- підтримуються всі вказані формати (
.jpg,.png,.gif). - файли перевищуючого розміру (більше 5 МБ) відхиляються з повідомленням про помилку.
- непідтримувані формати відхиляються з повідомленням про помилку.
- підтримуються всі вказані формати (
-
Роздача зображень:
- всі завантажені зображення доступні через Nginx за маршрутом
/images/<ім'я_файлу>.
- всі завантажені зображення доступні через Nginx за маршрутом
-
Логи:
- успішні завантаження та помилки записуються коректно.
- лог-файл зберігається між перезапусками контейнерів.
- Проект повністю запускається за допомогою однієї команди:
docker compose up --build- Всі залежності та конфігурації включені в проект.
- Написана інструкція з розгортання проекту, що включає:
- вимоги до оточення.
- команди для запуску та зупинки.
- опис структури проекту.
- опис маршрутів та їх функціональності.
Якщо всі вищезазначені критерії виконано, проект можна вважати успішно завершеним.
Простий веб-сервіс для завантаження та зберігання зображень: користувач завантажує картинку через веб-інтерфейс і отримує пряме посилання на неї.
Бекенд - Python (стандартна бібліотека + Pillow), роздача зображень і статики - Nginx, запуск - Docker Compose.
- завантаження
.jpg,.png,.gifрозміром до 5 МБ; - перевірка справжнього формату файлу через Pillow, а не за розширенням в імені;
- унікальні імена файлів (UUID), тож завантаження не перезаписують одне одного;
- прямі посилання виду
/images/<ім'я_файлу>, які роздає Nginx; - каталог завантажених зображень;
- логування всіх дій у
app.logу форматі[Дата/час] Дія: повідомлення; - зображення та логи живуть у Docker-томах і переживають перезапуск контейнерів.
Для запуску через Docker:
- Docker
- Docker Compose
Для запуску без Docker:
- Python 3.12 або новіший
- Pillow (
pip install -r requirements.txt)
З кореня проєкту:
docker compose up --buildПісля запуску доступні:
| Адреса | Що це |
|---|---|
http://localhost:8080/ |
сайт (через Nginx) - основна точка входу |
http://localhost:8080/images/<файл> |
пряме посилання на зображення |
http://localhost:8000/ |
бекенд напряму, лише для локального налагодження |
Зупинити контейнери (зображення та логи лишаються):
docker compose downЗупинити та видалити томи разом із даними:
docker compose down -vЗапуск без Docker (сервер підніметься на http://localhost:8000, зображення й логи - у теках images/ та logs/ у корені проєкту):
python app.py| Маршрут | Метод | Що робить | Хто обробляє |
|---|---|---|---|
/ |
GET | головна сторінка з описом сервісу та посиланнями | бекенд |
/upload |
GET | сторінка-форма завантаження | бекенд |
/upload |
POST | приймає файл, перевіряє, зберігає, повертає посилання | бекенд |
/images/ |
GET | каталог завантажених зображень | бекенд (Nginx проксує) |
/gallery |
GET | той самий каталог, прямий маршрут бекенду | бекенд |
/api/images |
GET | JSON-список імен завантажених файлів | бекенд |
/api/images/<файл> |
DELETE | видаляє зображення (кнопка "Видалити" в каталозі) | бекенд |
/images/<файл> |
GET | віддача самого зображення | Nginx |
Успішна відповідь POST /upload:
{"id": "3f2a1c....png", "url": "/images/3f2a1c....png"}Помилка (HTTP 400) - непідтримуваний формат, файл більший за 5 МБ, пошкоджений файл або запит не у форматі multipart/form-data:
{"error": "непідтримуваний формат файлу"}Завантажити зображення:
curl -F "image=@cat.jpg" http://localhost:8080/uploadЗабрати файл за посиланням:
curl -O http://localhost:8080/images/<унікальне>.jpgВидалити зображення:
curl -X DELETE http://localhost:8080/api/images/<унікальне>.jpgПеревірити обробку помилок:
curl -F "image=@document.txt" http://localhost:8080/uploadcurl -F "image=@huge.png" http://localhost:8080/uploadapp.py Python-бекенд: маршрути, валідація, збереження, логування
requirements.txt залежності Python (Pillow)
Dockerfile образ бекенду (multi-stage build)
compose.yaml опис сервісів app + nginx, томів і мережі
nginx.conf роздача /images/ та статики, проксування решти на бекенд
static/ HTML, CSS, JS інтерфейсу
tests/ юніт-тести бекенду
images/ локальна тека для зображень (у Docker - том images)
logs/ локальна тека для логів (у Docker - том logs)
- Nginx слухає
:8080і є єдиною зовнішньою точкою входу. /images/<файл>Nginx віддає сам із томуimages- Python при цьому не задіяний.- Статику (
/css/,/js/,/img/) Nginx теж роздає сам із текиstatic/. - Решту маршрутів Nginx проксує на
http://app:8000. - Тіло більше за 6 МБ Nginx відхиляє сам, підміняючи власний 413 на таку саму JSON-помилку 400, як у бекенду.
Лог пишеться у logs/app.log (том logs) у форматі з ТЗ:
[2026-01-24 14:00:00] Успіх: зображення 3f2a1c....png завантажено
[2026-01-24 14:01:00] Помилка: непідтримуваний формат файлу (document.txt)
Ті самі записи дублюються у docker compose logs app.
pip install -r requirements.txtpython -m unittest discover -s testsТести перевіряють:
- завантаження
.jpg,.png,.gif; - відмову для непідтримуваних форматів і для файлів більших за 5 МБ;
- відмову для файлу, який лише вдає із себе картинку розширенням;
- нестандартні записи межі
multipart(у лапках, із додатковим параметром); - роздачу збереженого зображення та список файлів у
/api/images; - видалення файлу через
DELETE /api/images/<файл>, зокрема відмову видаляти щось за межами теки зображень; - сторінки інтерфейсу,
HEAD, коди 404; - захист від виходу за межі теки зображень.