Skip to content

whynotdimaa/newsAPI

Repository files navigation

📰 News Site API — Блог-платформа з системою підписок

Сучасний REST API для новинного блогу з монетизацією через підписки, закріпленими постами та повною платіжною інтеграцією Stripe.

Python Django DRF PostgreSQL Redis Docker Celery Stripe


📋 Зміст


🎯 Про проект

News Site API — це повноцінний бекенд для новинного блогу з системою монетизації. Користувачі можуть реєструватися, публікувати пости, коментувати, а також придбати Premium підписку через Stripe, яка дозволяє закріплювати один пост у топі стрічки.

Проект побудований за принципами чистої архітектури: кожен модуль (accounts, main, comments, subscribe, payment) є незалежним Django-додатком зі своїми моделями, серіалізаторами, в'юшками та тестами.


🌐 Живе Демо

Проект задеплоєний на хмарному сервері з SSL-сертифікатом (Let's Encrypt) та доступний за адресою:

Сервіс URL
📘 Swagger UI newsapi.duckdns.org/api/docs/swagger/
📗 ReDoc newsapi.duckdns.org/api/docs/redoc/
⚙️ Django Admin newsapi.duckdns.org/admin/
🔗 API Root newsapi.duckdns.org/api/v1/

Стек деплою: VPS → Docker Compose → Gunicorn → Nginx → Let's Encrypt SSL → DuckDNS


✨ Особливості

👤 Користувачі та Автентифікація

  • JWT-Auth (access + refresh токени)
  • Реєстрація, вхід, вихід (blacklist токена), оновлення токена
  • Зміна паролю з валідацією старого
  • Профіль з аватаром, біографією, лічильниками постів та коментарів

📝 Пости та Категорії

  • CRUD для постів зі статусами draft / published
  • Автогенерація SEO-friendly slug із заголовку
  • Лічильник переглядів із автоінкрементом при кожному GET
  • Фільтрація за категорією, автором, статусом; пошук по тексту
  • Умовна видимість: анонімам — лише опубліковані; авторам — + власні чернетки
  • Спеціальні вибірки: популярні (топ-10 за переглядами), нещодавні, рекомендовані featured

💬 Коментарі

  • Дворівнева система: головні коментарі та відповіді (parent)
  • Soft delete — замість видалення встановлюється is_active=False
  • Дерево коментарів до поста з вкладеними відповідями

💎 Підписки

  • Тарифні плани з гнучкою конфігурацією (SubscriptionPlan)
  • Один активний Subscription на користувача (OneToOne)
  • Автоматичне встановлення дати завершення при активації
  • Відміна підписки з автоматичним видаленням закріпленого поста
  • Повна SubscriptionHistory — журнал усіх подій

📌 Закріплені пости (Premium фіча)

  • Лише підписники можуть закріпити один свій опублікований пост
  • Закріплені пости відображаються першими у стрічці
  • При закінченні підписки — закріплення знімається автоматично (Celery)
  • Валідація на рівні моделі (PinnedPost.save()) та серіалізатора

💳 Платежі (Stripe)

  • Stripe Checkout Session для безпечної оплати
  • Webhook-обробник для синхронізації статусів платежів
  • Повернення коштів (refund) через адмін-панель
  • Повна історія транзакцій з метаданими
  • Аналітика для адміністраторів (дохід, успішність, активні підписки)

🔄 Фонові задачі (Celery + Redis)

  • Перевірка прострочених підписок — щогодини
  • Email-нагадування про закінчення підписки — щодня
  • Очищення старих платежів — щотижня
  • Повторна обробка невдалих webhook-подій — щогодини

🛠️ Технічний стек

Компонент Технологія
Фреймворк Django 5.2 + Django REST Framework
База даних PostgreSQL 15
Кеш / Брокер Redis 7
Черги задач Celery + Celery Beat
Автентифікація JWT (SimpleJWT) з blacklist
Платежі Stripe (Checkout + Webhooks)
API Документація drf-spectacular (Swagger / ReDoc)
Контейнеризація Docker + Docker Compose
Веб-сервер Gunicorn + Nginx
SSL Let's Encrypt
pytest + pytest-django + Factory Boy + Faker

🏗️ Архітектура проекту

news-site/
├── apps/
│   ├── accounts/         # Реєстрація, авт-ція, профіль, зміна пароля
│   ├── main/             # Пости, категорії, закріплення
│   ├── comments/         # Коментарі (дворівневі, soft delete)
│   ├── subscribe/        # Підписки, плани, закріплені пости
│   │   ├── signals.py    # Автоматичне ведення history
│   │   └── tasks.py      # Перевірка прострочених підписок
│   └── payment/
│       ├── services.py   # StripeService, PaymentService, WebhookService
│       └── tasks.py      # Очищення та retry webhook
├── config/
│   ├── settings.py       # Налаштування Django
│   ├── celery.py         # Конфігурація Celery
│   └── urls.py           # Головний роутер
├── tests/                # pytest тести по кожному модулю
├── docker-compose.yml    # db, redis, backend, celery, nginx
├── Dockerfile
└── nginx.conf

Схема бази даних

User ──────────── Subscription ──── SubscriptionPlan
  │                    │
  │                    └── SubscriptionHistory
  │
  ├── Post ─────────── Category
  │     │
  │     └── Comment ── Comment (parent/replies)
  │
  ├── PinnedPost ───── Post
  │
  └── Payment ──────── Subscription
        └── PaymentAttempt
        └── Refund

Webhook (незалежна таблиця для Stripe events)

🚀 Швидкий старт

1. Клонуємо репозиторій

git clone https://github.com/whynotdimaa/newsAPI.git
cd newsAPI

2. Створюємо .env файл

SECRET_KEY=your-very-secret-django-key

DEBUG=False
DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1

# PostgreSQL
POSTGRES_DB=newssite
POSTGRES_USER=newsuser
POSTGRES_PASSWORD=your-strong-password
DB_HOST=db
DB_PORT=5432

# Stripe
STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

# Email (опціонально)
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
DEFAULT_FROM_EMAIL=noreply@newssite.com

# Redis / Celery
CELERY_BROKER_URL=redis://redis:6379/0
CELERY_RESULT_BACKEND=redis://redis:6379/0

# Frontend URL (для Stripe redirect)
FRONTEND_URL=http://localhost:5173

3. Запускаємо через Docker Compose

docker-compose up --build -d

Docker автоматично:

  • Застосує всі міграції
  • Зберере статику (Swagger/Admin)
  • Запустить Gunicorn, Celery Worker та Celery Beat

4. Створюємо суперкористувача

docker-compose exec backend python manage.py createsuperuser

5. Створюємо тарифний план підписки

docker-compose exec backend python manage.py create_subscription_product

Щоб прив'язати план до реального Stripe Price ID:

docker-compose exec backend python manage.py fix_stripe_integration

6. Доступні сервіси

Сервіс URL
API http://localhost/api/v1/
Swagger UI http://localhost/api/docs/swagger/
ReDoc http://localhost/api/docs/redoc/
Django Admin http://localhost/admin/

📡 API Документація

🔐 Автентифікація

Метод Ендпоінт Опис Auth
POST /api/v1/auth/register/ Реєстрація нового користувача
POST /api/v1/auth/login/ Вхід, отримання JWT токенів
POST /api/v1/auth/logout/ Вихід (blacklist refresh token)
GET /api/v1/auth/profile/ Отримати профіль
PUT/PATCH /api/v1/auth/profile/ Оновити профіль
PUT /api/v1/auth/change-password/ Змінити пароль
POST /api/v1/auth/token/refresh Оновити access token

📝 Пости

Метод Ендпоінт Опис Auth
GET /api/v1/posts/ Стрічка постів (з закріпленими першими)
POST /api/v1/posts/ Створити пост
GET /api/v1/posts/{slug}/ Деталі поста + інкремент переглядів
PUT/PATCH /api/v1/posts/{slug}/ Оновити пост (лише автор)
DELETE /api/v1/posts/{slug}/ Видалити пост (лише автор)
GET /api/v1/posts/my-posts/ Мої пости (+ чернетки)
GET /api/v1/posts/popular/ Топ-10 за переглядами
GET /api/v1/posts/recent/ 10 останніх постів
GET /api/v1/posts/featured/ 3 закріплених + 6 популярних за тиждень
GET /api/v1/posts/pinned/ Лише закріплені пости

📂 Категорії

Метод Ендпоінт Опис
GET /api/v1/posts/categories/ Список категорій з кількістю постів
POST /api/v1/posts/categories/ Створити категорію
GET/PUT/DELETE /api/v1/posts/categories/{slug}/ CRUD категорії
GET /api/v1/posts/categories/{slug}/posts/ Пости категорії (із закріпленими першими)

💬 Коментарі

Метод Ендпоінт Опис Auth
GET /api/v1/comments/ Всі активні коментарі
POST /api/v1/comments/ Створити коментар або відповідь
GET /api/v1/comments/{id}/ Деталі коментаря з відповідями
PATCH /api/v1/comments/{id}/ Редагувати коментар
DELETE /api/v1/comments/{id}/ Soft delete коментаря
GET /api/v1/comments/my-comments/ Мої коментарі
GET /api/v1/comments/post/{post_id}/ Коментарі поста (дерево)
GET /api/v1/comments/{id}/replies/ Відповіді на коментар

💎 Підписки

Метод Ендпоінт Опис Auth
GET /api/v1/subscribe/plans/ Доступні тарифні плани
GET /api/v1/subscribe/plans/{id}/ Деталі плану
GET /api/v1/subscribe/my-subscription/ Моя підписка
GET /api/v1/subscribe/status/ Статус підписки + чи можна закріплювати
GET /api/v1/subscribe/history/ Історія підписки
POST /api/v1/subscribe/cancel/ Відмінити підписку

📌 Закріплені пости

Метод Ендпоінт Опис Auth
GET /api/v1/subscribe/pinned-post/ Мій закріплений пост
POST /api/v1/subscribe/pin-post/ Закріпити пост
POST /api/v1/subscribe/unpin-post/ Відкріпити пост
GET /api/v1/subscribe/pinned-post/{post_id}/ Чи можна закріпити цей пост?

💳 Платежі

Метод Ендпоінт Опис Auth
POST /api/v1/payment/create-checkout-session/ Створити Stripe Checkout сесію
GET /api/v1/payment/payments/ Список моїх платежів
GET /api/v1/payment/payments/{id}/ Деталі платежу
GET /api/v1/payment/payments/{id}/status/ Статус платежу (синхронізація зі Stripe)
POST /api/v1/payment/payments/{id}/cancel/ Скасувати платіж
POST /api/v1/payment/payments/{id}/retry/ Повторна спроба оплати
GET /api/v1/payment/payments/history/ Повна історія транзакцій
POST /api/v1/payment/webhooks/stripe/ Stripe webhook endpoint
GET /api/v1/payment/analytics/ Фінансова аналітика (лише адмін) 🔑
POST /api/v1/payment/payments/{id}/refund/ Повернення коштів (лише адмін) 🔑

🔑 Автентифікація

API використовує JWT токени. Щоб отримати доступ до захищених ендпоінтів:

# 1. Отримати токени через логін
curl -X POST http://localhost/api/v1/auth/login/ \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com", "password": "yourpassword"}'

# Відповідь:
# { "access": "eyJ...", "refresh": "eyJ..." }

# 2. Використовувати access токен у запитах
curl http://localhost/api/v1/posts/my-posts/ \
  -H "Authorization: Bearer eyJ..."

Час життя токенів:

  • Access Token: 60 хвилин
  • Refresh Token: 7 днів (автооновлення при ротації)

🧪 Тестування

Проект використовує pytest + pytest-django:

# Запустити всі тести
docker-compose exec backend pytest

# З детальним виводом
docker-compose exec backend pytest -v

# Лише певний модуль
docker-compose exec backend pytest tests/test_posts.py
docker-compose exec backend pytest tests/test_subscribe.py

Покриття тестами:

  • tests/test_accounts.py — реєстрація, логін, профіль, зміна пароля
  • tests/test_posts.py — CRUD постів, права доступу, лічильник переглядів
  • tests/test_comments.py — коментарі, відповіді, soft delete
  • tests/test_subscribe.py — підписки, закріплення/відкріплення постів

⏰ Celery задачі

Задача Файл Розклад
Перевірка прострочених підписок subscribe/tasks.py Щогодини
Email нагадування (3 дні до кінця) subscribe/tasks.py Щодня
Очищення старих платежів (90+ днів) payment/tasks.py Щотижня
Очищення старих webhook-подій payment/tasks.py Щодня
Повторна обробка невдалих webhook payment/tasks.py Щогодини

📊 Адмін-панель

Django Admin (/admin/) надає повний контроль над усіма моделями:

  • Користувачі — пошук, фільтрація, права доступу
  • Пости та категорії — модерація, попередньо заповнений slug
  • Коментарі — масові дії (активувати/деактивувати)
  • Підписки — активація/відміна/протермінування одним кліком
  • Платежі — кольоровий статус, посилання на підписку, retry webhook
  • Refunds — повне та часткове повернення коштів

👤 Автор

@whynotdimaa README.md

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors