mirror of
https://github.com/EDeev/deev.space.git
synced 2026-10-07 20:49:59 +03:00
README на русском и английском, документация, скриншоты, лицензия MIT
- README.md и README.en.md: что это, статус, скриншоты, быстрый старт в Docker, установка без Docker, переменные окружения, схема, развёртывание, разработка; - docs/architecture.md (модели, оценки без регистрации, антинакрутка, безопасность) и docs/deploy.md (Docker и устройство боевого сервера) вместо описания моделей в README; - файл LICENSE (MIT), который раньше был заявлен только в README.
This commit is contained in:
parent
a04709d3df
commit
a696d996b9
10 changed files with 315 additions and 348 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2025 Egor Deev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
128
README.en.md
Normal file
128
README.en.md
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# deev.space
|
||||
|
||||
[Русский](README.md) · **English**
|
||||
|
||||
[](https://github.com/EDeev/deev.space/actions/workflows/ci.yml)
|
||||
[](https://github.com/EDeev/deev.space/actions/workflows/docker.yml)
|
||||
[](https://github.com/EDeev/deev.space/releases)
|
||||
[](LICENSE)
|
||||
|
||||
Personal portfolio website of a Python developer: projects, blog, experience and tech stack, article
|
||||
ratings without sign-up. Source code of [deev.space](https://deev.space).
|
||||
|
||||
**Status:** personal project, actively developed · live at [deev.space](https://deev.space)
|
||||
|
||||

|
||||
|
||||
**Stack:** Python 3.12 · Django 4.2 · SQLite · bleach · Yandex SmartCaptcha · gunicorn + nginx · Docker
|
||||
|
||||
## Features
|
||||
|
||||
- Home page with a profile card, tech stack by category and a "by the numbers" block
|
||||
- Blog: categories, galleries, attachments, links with automatic previews, threaded comments
|
||||
- Likes and dislikes without sign-up, based on a signed cookie and limited per IP
|
||||
- Unique article views with bot filtering
|
||||
- Projects, achievements, experience and education, all editable in the admin
|
||||
- Contact form with captcha and a Telegram notification to the owner
|
||||
- `sitemap.xml`, readable URLs, custom 404 and 500 pages
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
git clone https://github.com/EDeev/deev.space.git && cd deev.space
|
||||
cp .env.example .env # set DJANGO_SECRET_KEY
|
||||
docker compose up -d
|
||||
docker compose exec web python manage.py createsuperuser
|
||||
```
|
||||
|
||||
The site runs at `http://localhost:8000`, the admin at `/admin/`. Prebuilt image:
|
||||
`docker pull ghcr.io/edeev/deev.space` or `docker pull dcr.deev.su/edeev/deev.space`.
|
||||
|
||||
## Installing without Docker
|
||||
|
||||
```bash
|
||||
python -m venv .venv && source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
cp .env.example .env # for development: DJANGO_DEBUG=True
|
||||
python manage.py migrate
|
||||
python manage.py populate_demo # demo content, optional
|
||||
python manage.py createsuperuser
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
All settings are environment variables (full list in [`.env.example`](.env.example)):
|
||||
|
||||
| Variable | Purpose |
|
||||
|---|---|
|
||||
| `DJANGO_SECRET_KEY` | Django secret key, required with `DJANGO_DEBUG=False` |
|
||||
| `DJANGO_DEBUG` | debug mode, `False` by default |
|
||||
| `DJANGO_ALLOWED_HOSTS`, `DJANGO_CSRF_TRUSTED_ORIGINS` | comma-separated site domains |
|
||||
| `DJANGO_DB_PATH`, `DJANGO_MEDIA_ROOT` | location of the SQLite database and uploaded files |
|
||||
| `SMARTCAPTCHA_CLIENT_KEY`, `SMARTCAPTCHA_SERVER_KEY` | Yandex SmartCaptcha for the contact form |
|
||||
| `EMAIL_*`, `CONTACT_EMAIL` | sending contact form messages by email |
|
||||
| `ALERTBOT_TOKEN`, `ALERTBOT_CHAT_ID` | Telegram notification to the owner about a new message |
|
||||
| `SOCIAL_AUTOPOST`, `TELEGRAM_*`, `VK_*` | auto-posting new articles, off by default |
|
||||
|
||||
> [!IMPORTANT]
|
||||
> With `DJANGO_DEBUG=False` the site enables HSTS and redirects to HTTPS. To run without TLS (locally or
|
||||
> behind a proxy that terminates HTTPS), set `DJANGO_SECURE_SSL_REDIRECT=False`.
|
||||
|
||||
## Screenshots
|
||||
|
||||
| About | Projects |
|
||||
|---|---|
|
||||
|  |  |
|
||||
| **Blog** | **Mobile** |
|
||||
|  |  |
|
||||
|
||||
## How it works
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
B[Browser] --> N[nginx<br/>TLS, static, media]
|
||||
N --> G[gunicorn]
|
||||
G --> D[Django: main]
|
||||
D --> S[(SQLite)]
|
||||
D -.-> T[Telegram / AlertBot]
|
||||
D -.-> C[Yandex SmartCaptcha]
|
||||
```
|
||||
|
||||
A single `main` app: models for content, ratings and site settings, class-based views, a JSON API for
|
||||
ratings and comments, and an anonymous visitor middleware. Details (in Russian):
|
||||
|
||||
- [docs/architecture.md](docs/architecture.md) — models, ratings without sign-up, anti-abuse, security
|
||||
- [docs/deploy.md](docs/deploy.md) — running in Docker and how the production server is set up
|
||||
|
||||
## Deployment
|
||||
|
||||
[deev.space](https://deev.space) runs on a VPS: gunicorn under a dedicated user behind nginx with a
|
||||
Let's Encrypt certificate; nginx serves static files and uploads. Prometheus monitors availability and
|
||||
certificate expiry. GitHub Actions builds the Docker image on every `v*` tag and publishes it to GitHub
|
||||
Packages and to the `dcr.deev.su` registry.
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
pip install -r requirements-dev.txt
|
||||
ruff check . && pytest
|
||||
```
|
||||
|
||||
The tests (pytest-django) run in production mode and cover voting and anti-abuse, forms, escaping,
|
||||
pages and static files. CI runs the same checks on every push and pull request.
|
||||
|
||||
## License
|
||||
|
||||
MIT — see [LICENSE](LICENSE).
|
||||
|
||||
## Author
|
||||
|
||||
**Egor Deev** — [GitHub](https://github.com/EDeev) · [Telegram](https://t.me/DeevEgor) · [egor@deev.space](mailto:egor@deev.space)
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<sub>⭐ If you find this project useful, give it a star on GitHub!</sub>
|
||||
<p><sub>Made with ❤️ — <a href="https://deev.space">deev.space</a></sub></p>
|
||||
</div>
|
||||
431
README.md
431
README.md
|
|
@ -1,393 +1,128 @@
|
|||
# deev.space
|
||||
|
||||
<div align="center">
|
||||
<img src="https://img.shields.io/badge/Python-3.8+-blue.svg" alt="Python Version">
|
||||
<img src="https://img.shields.io/badge/Django-4.2+-green.svg" alt="Django Version">
|
||||
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License">
|
||||
<img src="https://img.shields.io/badge/Status-Production-brightgreen.svg" alt="Status">
|
||||
</div>
|
||||
**Русский** · [English](README.en.md)
|
||||
|
||||
Профессиональный персональный веб-сайт портфолио backend-разработчика, созданный на Django. Проект представляет собой полнофункциональную платформу с системой управления контентом, блог-системой с комментариями, интерактивным портфолио проектов и современным адаптивным дизайном.
|
||||
[](https://github.com/EDeev/deev.space/actions/workflows/ci.yml)
|
||||
[](https://github.com/EDeev/deev.space/actions/workflows/docker.yml)
|
||||
[](https://github.com/EDeev/deev.space/releases)
|
||||
[](LICENSE)
|
||||
|
||||
## 🌟 Основные возможности
|
||||
Персональный сайт-портфолио Python-разработчика: проекты, блог, опыт и стек, оценки статей без
|
||||
регистрации. Исходный код сайта [deev.space](https://deev.space).
|
||||
|
||||
- **Система управления контентом** через расширенную Django Admin панель с кастомными инлайнами и фильтрами
|
||||
- **Блог-платформа** с поддержкой категорий, комментариев, лайков/дизлайков, галерей изображений и прикрепленных файлов
|
||||
- **Портфолио проектов** с гибкой системой фильтрации по языкам программирования, технологиям и статусам
|
||||
- **Страница достижений** для демонстрации наград и сертификатов
|
||||
- **Многоуровневая система комментариев** с возможностью оценки и вложенности до 3 уровней
|
||||
- **Интеграция с социальными сетями** для автоматической публикации новых статей в Telegram и VKontakte
|
||||
- **Адаптивный дизайн** с поддержкой всех современных устройств и разрешений
|
||||
- **SEO-оптимизация** включая динамический sitemap, schema.org разметку и Open Graph метатеги
|
||||
- **Продвинутая аналитика** с интеграцией Яндекс.Метрики и Google Analytics
|
||||
- **Безопасность** с использованием Yandex SmartCaptcha и защитой от CSRF/XSS атак
|
||||
**Статус:** личный проект, активно развивается · работает на [deev.space](https://deev.space)
|
||||
|
||||
## 🛠 Технологический стек
|
||||

|
||||
|
||||
**Backend:**
|
||||
- Python 3.8+
|
||||
- Django 4.2+
|
||||
- SQLite (разработка) / PostgreSQL (продакшн)
|
||||
- Pillow для обработки изображений
|
||||
- Bleach для санитизации HTML
|
||||
- BeautifulSoup4 для парсинга метаданных ссылок
|
||||
- Requests для HTTP запросов
|
||||
**Стек:** Python 3.12 · Django 4.2 · SQLite · bleach · Yandex SmartCaptcha · gunicorn + nginx · Docker
|
||||
|
||||
**Frontend:**
|
||||
- HTML5, CSS3 с использованием CSS Custom Properties
|
||||
- Vanilla JavaScript (ES6+)
|
||||
- Font Awesome 6.5 для иконок
|
||||
- Devicon для технологических иконок
|
||||
- AOS (Animate On Scroll) для анимаций
|
||||
- Prism.js для подсветки синтаксиса кода
|
||||
- Google Fonts (Raleway, Inter)
|
||||
## Возможности
|
||||
|
||||
**Интеграции:**
|
||||
- Yandex SmartCaptcha для защиты форм
|
||||
- Telegram Bot API для автопостинга
|
||||
- VK API для публикации в группы
|
||||
- Schema.org для структурированных данных
|
||||
- Главная с карточкой-паспортом, стеком по категориям и блоком «В цифрах»
|
||||
- Блог: категории, галереи, вложения, ссылки с автоматическим превью, комментарии с ответами
|
||||
- Лайки и дизлайки без регистрации — по подписанной cookie, с лимитом оценок с одного IP
|
||||
- Уникальные просмотры статей с фильтром ботов
|
||||
- Проекты, достижения, опыт и образование — весь контент редактируется в админке
|
||||
- Форма обратной связи с капчей и уведомлением владельцу в Telegram
|
||||
- `sitemap.xml`, человекопонятные адреса, свои страницы 404 и 500
|
||||
|
||||
**Инфраструктура:**
|
||||
- Nginx как веб-сервер и reverse proxy
|
||||
- Gunicorn для WSGI сервера
|
||||
- Supervisor для управления процессами
|
||||
- Let's Encrypt для SSL сертификатов
|
||||
## Быстрый старт
|
||||
|
||||
## 📁 Структура проекта
|
||||
```
|
||||
deev.space/
|
||||
├── main/ # Основное Django приложение
|
||||
│ ├── migrations/ # Миграции базы данных
|
||||
│ ├── templatetags/ # Кастомные теги и фильтры
|
||||
│ │ └── custom_filters.py # Фильтры для технологий, времени чтения
|
||||
│ ├── models.py # Модели данных
|
||||
│ ├── views.py # Представления и бизнес-логика
|
||||
│ ├── forms.py # Формы с валидацией
|
||||
│ ├── admin.py # Административная панель
|
||||
│ ├── signals.py # Сигналы для автопостинга
|
||||
│ ├── sitemaps.py # Генерация sitemap
|
||||
│ ├── context_processors.py # Глобальные контекстные данные
|
||||
│ └── urls.py # URL маршруты
|
||||
├── dspace/ # Конфигурация Django проекта
|
||||
│ ├── settings.py # Настройки приложения
|
||||
│ ├── urls.py # Корневые URL паттерны
|
||||
│ ├── wsgi.py # WSGI точка входа
|
||||
│ └── asgi.py # ASGI точка входа
|
||||
├── templates/ # HTML шаблоны
|
||||
│ ├── wrapper.html # Базовый шаблон с SEO
|
||||
│ ├── index.html # Главная страница
|
||||
│ ├── about.html # Страница "Обо мне"
|
||||
│ ├── projects.html # Портфолио проектов
|
||||
│ ├── achievements.html # Достижения
|
||||
│ ├── contacts.html # Контакты и форма обратной связи
|
||||
│ ├── blog/ # Шаблоны блога
|
||||
│ │ ├── blog.html # Список статей
|
||||
│ │ └── article.html # Детальная страница статьи
|
||||
│ ├── auth/ # Шаблоны аутентификации
|
||||
│ │ ├── login.html # Вход
|
||||
│ │ └── register.html # Регистрация
|
||||
│ ├── errors/ # Страницы ошибок
|
||||
│ │ ├── 404.html # Страница не найдена
|
||||
│ │ └── 500.html # Ошибка сервера
|
||||
│ ├── includes/ # Переиспользуемые компоненты
|
||||
│ │ ├── project_card.html # Карточка проекта
|
||||
│ │ ├── comments.html # Рекурсивные комментарии
|
||||
│ │ └── pagination.html # Пагинация
|
||||
│ └── widgets/ # Кастомные виджеты
|
||||
│ └── smartcaptcha.html # Yandex SmartCaptcha
|
||||
├── static/ # Статические файлы
|
||||
│ ├── css/ # Стили
|
||||
│ │ ├── variables.css # CSS переменные и дизайн-токены
|
||||
│ │ ├── base.css # Базовые стили и типографика
|
||||
│ │ ├── components.css # Переиспользуемые компоненты
|
||||
│ │ ├── layout.css # Раскладка и сетки
|
||||
│ │ ├── projects.css # Стили проектов
|
||||
│ │ ├── blog.css # Стили блога
|
||||
│ │ ├── pages.css # Страничные стили
|
||||
│ │ └── media.css # Медиа-запросы
|
||||
│ ├── js/ # JavaScript
|
||||
│ │ └── main.js # Основная логика фронтенда
|
||||
│ └── img/ # Изображения
|
||||
│ ├── logo.png # Логотип
|
||||
│ └── favicon.ico # Фавикон
|
||||
├── media/ # Загружаемые файлы
|
||||
│ ├── articles/ # Изображения статей
|
||||
│ │ ├── gallery/ # Галереи статей
|
||||
│ │ └── files/ # Прикрепленные файлы
|
||||
│ ├── projects/ # Изображения проектов
|
||||
│ ├── avatars/ # Аватары пользователей
|
||||
│ └── site/ # Настройки сайта
|
||||
├── logs/ # Логи приложения
|
||||
├── requirements.txt # Python зависимости
|
||||
├── manage.py # Django CLI утилита
|
||||
└── README.md # Документация
|
||||
```
|
||||
|
||||
## 🚀 Быстрый старт
|
||||
|
||||
### Предварительные требования
|
||||
|
||||
Перед началом работы убедитесь, что установлены следующие компоненты:
|
||||
|
||||
- Python 3.8 или выше
|
||||
- pip (менеджер пакетов Python)
|
||||
- virtualenv или venv (рекомендуется)
|
||||
- Git для клонирования репозитория
|
||||
|
||||
### Установка и запуск
|
||||
|
||||
**Шаг 1. Клонирование репозитория**
|
||||
```bash
|
||||
git clone https://github.com/EDeev/deev.space.git
|
||||
cd deev.space
|
||||
git clone https://github.com/EDeev/deev.space.git && cd deev.space
|
||||
cp .env.example .env # задайте DJANGO_SECRET_KEY
|
||||
docker compose up -d
|
||||
docker compose exec web python manage.py createsuperuser
|
||||
```
|
||||
|
||||
**Шаг 2. Создание виртуального окружения**
|
||||
```bash
|
||||
python -m venv venv
|
||||
|
||||
# Для Linux/macOS:
|
||||
source venv/bin/activate
|
||||
|
||||
# Для Windows:
|
||||
venv\Scripts\activate
|
||||
```
|
||||
|
||||
**Шаг 3. Установка зависимостей**
|
||||
Сайт откроется на `http://localhost:8000`, админка — на `/admin/`. Готовый образ:
|
||||
`docker pull ghcr.io/edeev/deev.space` или `docker pull dcr.deev.su/edeev/deev.space`.
|
||||
|
||||
## Установка без Docker
|
||||
|
||||
```bash
|
||||
python -m venv .venv && source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
**Шаг 4. Настройка переменных окружения**
|
||||
|
||||
Создайте файл `.env` в корне проекта со следующим содержимым:
|
||||
```env
|
||||
# Django
|
||||
DJANGO_SECRET_KEY=your-secret-key-here
|
||||
DJANGO_DEBUG=True
|
||||
|
||||
# Email
|
||||
EMAIL_HOST=smtp.yandex.ru
|
||||
EMAIL_PORT=465
|
||||
EMAIL_HOST_USER=your-email@example.com
|
||||
EMAIL_HOST_PASSWORD=your-password
|
||||
DEFAULT_FROM_EMAIL=your-email@example.com
|
||||
CONTACT_EMAIL=your-email@example.com
|
||||
|
||||
# Yandex SmartCaptcha
|
||||
SMARTCAPTCHA_CLIENT_KEY=your-client-key
|
||||
SMARTCAPTCHA_SERVER_KEY=your-server-key
|
||||
|
||||
# Telegram (опционально)
|
||||
TELEGRAM_BOT_TOKEN=your-bot-token
|
||||
TELEGRAM_CHANNEL_ID=your-channel-id
|
||||
|
||||
# VK (опционально)
|
||||
VK_ACCESS_TOKEN=your-access-token
|
||||
VK_GROUP_ID=your-group-id
|
||||
```
|
||||
|
||||
**Шаг 5. Применение миграций базы данных**
|
||||
```bash
|
||||
cp .env.example .env # для разработки: DJANGO_DEBUG=True
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
**Шаг 6. Создание суперпользователя**
|
||||
```bash
|
||||
python manage.py populate_demo # демо-контент, по желанию
|
||||
python manage.py createsuperuser
|
||||
```
|
||||
|
||||
Следуйте инструкциям для создания учетной записи администратора.
|
||||
|
||||
**Шаг 7. Сбор статических файлов**
|
||||
```bash
|
||||
python manage.py collectstatic --noinput
|
||||
```
|
||||
|
||||
**Шаг 8. Запуск сервера разработки**
|
||||
```bash
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
Сайт будет доступен по адресу: `http://127.0.0.1:8000`
|
||||
## Конфигурация
|
||||
|
||||
Административная панель: `http://127.0.0.1:8000/admin`
|
||||
Все настройки — переменные окружения (полный список — [`.env.example`](.env.example)):
|
||||
|
||||
## 📊 Модели данных
|
||||
| Переменная | Назначение |
|
||||
|---|---|
|
||||
| `DJANGO_SECRET_KEY` | секретный ключ Django, обязателен при `DJANGO_DEBUG=False` |
|
||||
| `DJANGO_DEBUG` | режим отладки, по умолчанию `False` |
|
||||
| `DJANGO_ALLOWED_HOSTS`, `DJANGO_CSRF_TRUSTED_ORIGINS` | домены сайта через запятую |
|
||||
| `DJANGO_DB_PATH`, `DJANGO_MEDIA_ROOT` | где лежат база SQLite и загруженные файлы |
|
||||
| `SMARTCAPTCHA_CLIENT_KEY`, `SMARTCAPTCHA_SERVER_KEY` | Yandex SmartCaptcha для формы обратной связи |
|
||||
| `EMAIL_*`, `CONTACT_EMAIL` | отправка писем с формы обратной связи |
|
||||
| `ALERTBOT_TOKEN`, `ALERTBOT_CHAT_ID` | уведомление владельцу в Telegram о новом сообщении |
|
||||
| `SOCIAL_AUTOPOST`, `TELEGRAM_*`, `VK_*` | автопостинг новых статей, по умолчанию выключен |
|
||||
|
||||
### SiteSettings (Настройки сайта)
|
||||
Singleton модель для управления глобальными настройками сайта через административную панель. Включает информацию о владельце, контакты, социальные сети и файлы.
|
||||
> [!IMPORTANT]
|
||||
> С `DJANGO_DEBUG=False` сайт включает HSTS и редирект на HTTPS. Для запуска без TLS (локально или за
|
||||
> прокси, который сам терминирует HTTPS) задайте `DJANGO_SECURE_SSL_REDIRECT=False`.
|
||||
|
||||
**Основные поля:**
|
||||
- `site_name`, `site_description` - название и описание сайта
|
||||
- `owner_name`, `owner_title`, `owner_bio` - информация о владельце
|
||||
- `owner_photo` - фотография
|
||||
- `owner_email`, `owner_phone`, `owner_city` - контактные данные
|
||||
- `telegram_url`, `github_url`, `vk_url`, `linkedin_url` - социальные сети
|
||||
- `resume_file` - файл резюме
|
||||
## Как выглядит
|
||||
|
||||
### Article (Статьи блога и достижения)
|
||||
Универсальная модель для статей блога и достижений с поддержкой мультимедиа контента.
|
||||
| О себе | Проекты |
|
||||
|---|---|
|
||||
|  |  |
|
||||
| **Блог** | **Мобильная версия** |
|
||||
|  |  |
|
||||
|
||||
**Основные поля:**
|
||||
- `title`, `slug`, `sub_title` - заголовки и URL
|
||||
- `excerpt`, `post` - описание и содержание
|
||||
- `img` - превью изображение
|
||||
- `category` - категория статьи
|
||||
- `is_published` - статус публикации
|
||||
- `comments_enabled` - включение комментариев
|
||||
- `is_achievement` - флаг достижения
|
||||
- `views`, `date`, `updated_at` - метаданные
|
||||
## Как устроено
|
||||
|
||||
**Связанные модели:**
|
||||
- `ArticleImage` - галерея изображений
|
||||
- `ArticleFile` - прикрепленные файлы
|
||||
- `ArticleLink` - прикрепленные ссылки с автоматическим парсингом метаданных
|
||||
|
||||
### Project (Портфолио проектов)
|
||||
Модель для управления проектами с гибкой системой статусов и отображения.
|
||||
|
||||
**Основные поля:**
|
||||
- `title`, `slug` - название и URL
|
||||
- `short_description`, `description` - описания
|
||||
- `features` - список особенностей
|
||||
- `programming_languages` - языки программирования
|
||||
- `technologies` - используемые технологии
|
||||
- `status` - связь с ProjectStatus
|
||||
- `card_size` - размер карточки (featured/regular/small)
|
||||
- `show_on_homepage`, `homepage_order` - отображение на главной
|
||||
- `github_url`, `demo_url` - ссылки
|
||||
|
||||
### Experience (Опыт работы)
|
||||
Детальная информация о профессиональном опыте.
|
||||
|
||||
**Основные поля:**
|
||||
- `title`, `company`, `company_url` - должность и компания
|
||||
- `description`, `responsibilities` - описание и обязанности
|
||||
- `technologies` - используемые технологии
|
||||
- `start_date`, `end_date`, `is_current` - период работы
|
||||
- Автоматический расчет продолжительности через свойство `duration`
|
||||
|
||||
### Education (Образование)
|
||||
Информация об образовании с поддержкой различных типов.
|
||||
|
||||
**Основные поля:**
|
||||
- `institution`, `degree` - учебное заведение и специальность
|
||||
- `education_type` - тип (университет/курс/школа)
|
||||
- `achievements` - список достижений
|
||||
- `start_year`, `end_year`, `is_current` - период обучения
|
||||
- `certificate_number`, `certificate_url` - сертификаты
|
||||
|
||||
### Comment (Комментарии)
|
||||
Многоуровневая система комментариев с поддержкой вложенности.
|
||||
|
||||
**Основные поля:**
|
||||
- `article`, `user`, `parent` - связи
|
||||
- `content` - содержание комментария
|
||||
- `is_approved` - модерация
|
||||
- Автоматический расчет уровня вложенности через `nesting_level`
|
||||
- Подсчет лайков/дизлайков через `CommentLike`
|
||||
|
||||
### CustomUser (Пользователи)
|
||||
Расширенная модель пользователя Django.
|
||||
|
||||
**Дополнительные поля:**
|
||||
- `email` - опциональный email
|
||||
- `is_verified` - статус верификации
|
||||
- `avatar` - аватар пользователя
|
||||
|
||||
## ⚙️ Конфигурация
|
||||
|
||||
### Основные настройки производства
|
||||
|
||||
Для развертывания в продакшн среде необходимо изменить следующие параметры в `dspace/settings.py`:
|
||||
```python
|
||||
# Безопасность
|
||||
DEBUG = False
|
||||
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
|
||||
ALLOWED_HOSTS = ['deev.space', 'www.deev.space']
|
||||
|
||||
# База данных (рекомендуется PostgreSQL)
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': 'deevspace_db',
|
||||
'USER': 'deevspace_user',
|
||||
'PASSWORD': os.environ.get('DB_PASSWORD'),
|
||||
'HOST': 'localhost',
|
||||
'PORT': '5432',
|
||||
}
|
||||
}
|
||||
|
||||
# Безопасность
|
||||
SECURE_SSL_REDIRECT = True
|
||||
SECURE_HSTS_SECONDS = 31536000
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||
SECURE_HSTS_PRELOAD = True
|
||||
SESSION_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
```mermaid
|
||||
flowchart LR
|
||||
B[Браузер] --> N[nginx<br/>TLS, static, media]
|
||||
N --> G[gunicorn]
|
||||
G --> D[Django: main]
|
||||
D --> S[(SQLite)]
|
||||
D -.-> T[Telegram / AlertBot]
|
||||
D -.-> C[Yandex SmartCaptcha]
|
||||
```
|
||||
|
||||
### Настройка интеграций
|
||||
Одно приложение `main`: модели контента, оценок и настроек сайта, классовые представления, JSON-API
|
||||
для оценок и комментариев, middleware анонимного посетителя. Подробности:
|
||||
|
||||
**Автопостинг в Telegram:**
|
||||
Настройте переменные окружения `TELEGRAM_BOT_TOKEN` и `TELEGRAM_CHANNEL_ID`. При публикации новой статьи автоматически отправляется пост в канал.
|
||||
- [docs/architecture.md](docs/architecture.md) — модели, оценки без регистрации, антинакрутка, безопасность
|
||||
- [docs/deploy.md](docs/deploy.md) — запуск в Docker и как устроен боевой сервер
|
||||
|
||||
**Автопостинг в VKontakte:**
|
||||
Настройте `VK_ACCESS_TOKEN` и `VK_GROUP_ID` для автоматической публикации в группу VK.
|
||||
## Развёртывание
|
||||
|
||||
**Email уведомления:**
|
||||
Настройте SMTP параметры для отправки уведомлений через контактную форму.
|
||||
[deev.space](https://deev.space) работает на VPS: gunicorn под отдельным пользователем за nginx с
|
||||
сертификатом Let's Encrypt, статика и загрузки отдаются nginx. Доступность и срок сертификата
|
||||
отслеживает Prometheus. Docker-образ собирает GitHub Actions на каждый тег `v*` и публикует в GitHub
|
||||
Packages и в реестр `dcr.deev.su`.
|
||||
|
||||
## 🌐 Развертывание
|
||||
## Разработка
|
||||
|
||||
Можете прочитать о развёртывании проекта на сервере в <a href="https://deev.space/blog/razvertyvanie-django-proekta-na-servere-s-nulya-do-https/">статье на моём сайте</a>.
|
||||
```bash
|
||||
pip install -r requirements-dev.txt
|
||||
ruff check . && pytest
|
||||
```
|
||||
|
||||
## 📈 Аналитика и мониторинг
|
||||
Тесты (pytest-django) запускаются в боевом режиме: голосование и антинакрутка, формы, экранирование,
|
||||
страницы и статика. CI выполняет то же самое на каждый push и pull request.
|
||||
|
||||
Проект интегрирован с системами аналитики для отслеживания поведения пользователей:
|
||||
## Лицензия
|
||||
|
||||
**Яндекс.Метрика:**
|
||||
Автоматически загружается при наличии `YANDEX_METRIKA_ID` в настройках. Отслеживает посещаемость, карты кликов, вебвизор и другие метрики.
|
||||
MIT — см. [LICENSE](LICENSE).
|
||||
|
||||
**Google Analytics:**
|
||||
Подключается при указании `GOOGLE_ANALYTICS_ID`. Предоставляет детальную аналитику трафика и поведения пользователей.
|
||||
## Автор
|
||||
|
||||
**Логирование:**
|
||||
Настроено детальное логирование с записью ошибок в файлы и вывод информационных сообщений в консоль.
|
||||
|
||||
## 🛡️ Безопасность
|
||||
|
||||
Проект реализует следующие меры безопасности:
|
||||
|
||||
- **CSRF Protection** - защита от межсайтовых запросов через Django middleware
|
||||
- **XSS Protection** - санитизация пользовательского ввода с помощью Bleach
|
||||
- **SQL Injection Protection** - использование Django ORM
|
||||
- **Yandex SmartCaptcha** - защита форм от ботов
|
||||
- **HTTPS Redirect** - принудительное перенаправление на защищенное соединение
|
||||
- **HSTS Headers** - заголовки безопасности для браузеров
|
||||
- **Secure Cookies** - защищенные cookies для сессий
|
||||
- **Content Security Policy** - настроенные заголовки безопасности
|
||||
- **Rate Limiting** - защита от перегрузки (рекомендуется настроить на уровне Nginx)
|
||||
|
||||
## 👨💻 Автор и контакты
|
||||
|
||||
**Деев Егор Викторович**
|
||||
Backend Developer | Python Specialist
|
||||
|
||||
- **Веб-сайт:** [deev.space](https://deev.space)
|
||||
- **GitHub:** [@EDeev](https://github.com/EDeev)
|
||||
- **Email:** egor@deev.space
|
||||
- **Telegram:** [@Egor_Deev](https://t.me/Egor_Deev)
|
||||
|
||||
## 📄 Лицензия
|
||||
|
||||
Этот проект является некоммерческим и распространяется под лицензией MIT.
|
||||
**Деев Егор Викторович** — [GitHub](https://github.com/EDeev) · [Telegram](https://t.me/DeevEgor) · [egor@deev.space](mailto:egor@deev.space)
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<sub>⭐ Если проект оказался полезным, поставьте звездочку на GitHub!</sub>
|
||||
<p><sub>Создано с ❤️ от вашего дорогого - <a href="https://deev.space">deev.space</a> ©</sub></p>
|
||||
<sub>⭐ Если проект оказался полезным, поставьте звёздочку на GitHub!</sub>
|
||||
<p><sub>Сделано с ❤️ — <a href="https://deev.space">deev.space</a></sub></p>
|
||||
</div>
|
||||
|
|
|
|||
51
docs/architecture.md
Normal file
51
docs/architecture.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Как устроен deev.space
|
||||
|
||||
Django-проект `dspace` с одним приложением `main`. База — SQLite, статика — whitenoise (в бою — nginx),
|
||||
шаблоны — Django templates, без фронтенд-фреймворков.
|
||||
|
||||
```
|
||||
dspace/ настройки, корневые URL, WSGI
|
||||
main/
|
||||
models.py модели контента, оценок и настроек сайта
|
||||
views.py страницы (классовые представления) и JSON-API оценок и комментариев
|
||||
forms.py формы с очисткой HTML (bleach) и Yandex SmartCaptcha
|
||||
middleware.py анонимный ID посетителя, хэш IP, фильтр ботов
|
||||
signals.py действия после публикации статьи (автопостинг, ping Яндекса)
|
||||
admin.py админка с превью и инлайнами медиа статьи
|
||||
management/ load_initial_data, populate_demo
|
||||
templates/ шаблоны страниц, включая includes/ и errors/
|
||||
static/ CSS по слоям (variables, base, components, layout, pages, media), JS
|
||||
```
|
||||
|
||||
## Модели
|
||||
|
||||
| Модель | Назначение |
|
||||
|---|---|
|
||||
| `SiteSettings` | синглтон с текстами сайта, контактами, карточкой-паспортом (`SiteSettings.load()`) |
|
||||
| `CustomUser` | пользователь для комментариев, упрощённая регистрация |
|
||||
| `Category`, `Article` | статьи блога и достижения (`is_achievement`); slug генерируется из заголовка |
|
||||
| `ArticleImage`, `ArticleFile`, `ArticleLink` | галерея, вложения и ссылки статьи; у ссылок — автоматическое превью по Open Graph |
|
||||
| `Project`, `ProjectStatus` | проекты портфолио с гибкими статусами |
|
||||
| `Skill`, `Experience`, `Education` | стек по категориям, опыт и образование |
|
||||
| `Comment` | комментарии с ответами до трёх уровней вложенности |
|
||||
| `ArticleLike`, `CommentLike` | лайки и дизлайки — от пользователя или анонимного посетителя |
|
||||
| `ArticleView` | уникальный просмотр статьи (один на посетителя) |
|
||||
| `ContactMessage` | сообщения с формы обратной связи |
|
||||
|
||||
## Оценки без регистрации
|
||||
|
||||
1. `VisitorMiddleware` выдаёт каждому посетителю подписанную cookie `dspace_vid` (uuid4, httponly, год).
|
||||
2. Голос привязан к аккаунту, если пользователь вошёл, иначе — к `visitor_id`. Повторный клик снимает
|
||||
голос, клик по противоположной кнопке меняет его.
|
||||
3. Антинакрутка: с одного хэша «IP + User-Agent» (соль — `SECRET_KEY`) — не больше двух новых
|
||||
анонимных оценок одного объекта в сутки. Для loopback и частных адресов хэш не считается, лимит не
|
||||
применяется.
|
||||
4. Уникальные просмотры (`ArticleView`) пишутся только для посетителей, которых `is_bot()` не
|
||||
считает роботами.
|
||||
|
||||
## Безопасность
|
||||
|
||||
- HTML комментариев проходит через `bleach` (белый список тегов), из формы обратной связи вырезается весь.
|
||||
- Форма обратной связи защищена Yandex SmartCaptcha.
|
||||
- Превью ссылок загружаются только с публичных http(s)-адресов.
|
||||
- С `DJANGO_DEBUG=False`: HSTS, редирект на HTTPS, secure-cookie; без `DJANGO_SECRET_KEY` запуск невозможен.
|
||||
32
docs/deploy.md
Normal file
32
docs/deploy.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# Развёртывание
|
||||
|
||||
## Docker
|
||||
|
||||
```bash
|
||||
cp .env.example .env # задайте DJANGO_SECRET_KEY и при необходимости ключи капчи и почты
|
||||
docker compose up -d
|
||||
docker compose exec web python manage.py createsuperuser
|
||||
```
|
||||
|
||||
База и загруженные файлы хранятся в томе `data` (`/data/db.sqlite3`, `/data/media`). Готовый образ
|
||||
собирается GitHub Actions на каждый тег `v*`:
|
||||
|
||||
```bash
|
||||
docker pull ghcr.io/edeev/deev.space:latest
|
||||
docker pull dcr.deev.su/edeev/deev.space:latest
|
||||
```
|
||||
|
||||
За обратным прокси укажите домены в `DJANGO_ALLOWED_HOSTS` и `DJANGO_CSRF_TRUSTED_ORIGINS`, а
|
||||
`DJANGO_SERVE_MEDIA` выключите и отдавайте `/media/` прокси-сервером.
|
||||
|
||||
## Как работает deev.space
|
||||
|
||||
Боевой сайт крутится на VPS без Docker:
|
||||
|
||||
- gunicorn под отдельным пользователем `dspace`, systemd-юнит, unix-сокет;
|
||||
- nginx отдаёт `/static/` и `/media/` с диска и проксирует остальное в сокет, TLS — Let's Encrypt;
|
||||
- переменные окружения — в `.env` рядом с проектом;
|
||||
- обновление: выложить код, `pip install -r requirements.txt`, `python manage.py migrate`,
|
||||
`python manage.py collectstatic --noinput`, перезапуск юнита;
|
||||
- доступность сайта и срок сертификата проверяет Prometheus (blackbox exporter), уведомления
|
||||
о новых сообщениях с формы приходят в Telegram через AlertBot.
|
||||
BIN
docs/screenshots/about.png
Normal file
BIN
docs/screenshots/about.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 206 KiB |
BIN
docs/screenshots/blog.png
Normal file
BIN
docs/screenshots/blog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 157 KiB |
BIN
docs/screenshots/main.png
Normal file
BIN
docs/screenshots/main.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 261 KiB |
BIN
docs/screenshots/mobile.png
Normal file
BIN
docs/screenshots/mobile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 430 KiB |
BIN
docs/screenshots/projects.png
Normal file
BIN
docs/screenshots/projects.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 330 KiB |
Loading…
Add table
Reference in a new issue