Minimal social network built with Django 5, PostgreSQL, and Bootstrap 5.
Focuses on clean architecture, security-first authentication, and production-ready features:
email-based auth with CAPTCHA protection, user profiles, posts, comments, likes, follows, DMs,
notifications, and a small but well-structured REST API.
👤🔐 User Authentication
- Custom User model with email as login (
USERNAME_FIELD = email) - Sign up / sign in / sign out
- Email confirmation & password reset (console backend in dev)
- Auth via Google (OAuth2)
🛡️ Authentication protected with CAPTCHA
- Login & registration are protected with Cloudflare Turnstile CAPTCHA
- Implemented via
django-turnstile
📝 Content
- Create / edit / delete posts (image + tags)
- Comments with reply support, soft-delete and edit tracking
- Likes with a
likes_countcounter on posts
📄 User Profiles
- Avatar, birthday, editable profile fields
- Profile page with posts, followers and stats
🔁 Subscriptions / Follow
- Follow / unfollow users with follower counts
- Personalized feeds (posts from followed users)
🔔 Notifications
- In-app notification model
- Small internal API to mark notifications as read
💬 Messaging
- Direct messages with Conversation / Participant / Message models
🔌 REST API
- DRF-based endpoints (posts CRUD, search, ordering)
- Swagger / OpenAPI docs at
/api/docs/(via drf-spectacular)
🌓 Theme Switcher
- Built-in
light / dark modetoggle for the UI - Respects system preferences and persists user choice
🧊 Snowfall Effect
- Modern snowfall animation rendered on a full-page canvas
- Automatically adapts to the active UI theme (
light/dark) for optimal contrast - Non-intrusive (
pointer-events: none) and performance-friendly (requestAnimationFrame)
📊 Monitoring (Prometheus + Grafana + Alertmanager)
- Application-level metrics (Django)
- Infrastructure and container metrics
- Health checks and uptime monitoring
- Alerting (ready for future extensions)
⚙️ Admin & Dev Tooling
- Django admin configured for users, posts, comments and notifications
- Fully Dockerized application
- Entrypoint script runs migrations and collects static files
- Python: 3.11+
- Django: 5.x
- DB: PostgreSQL (docker compose uses
postgres:15) - API: DRF, drf‑spectacular (optional)
- Auth: django‑allauth (email login)
- Storage: local filesystem by default (S3/MinIO optional)
- Deps: Poetry
- UI: Django Templates + Bootstrap 5
Post (simplified) used in this build:
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="posts")
title = models.CharField(max_length=100)
text = models.TextField(max_length=2500)
image = models.ImageField(null=True, blank=True, upload_to="posts/img/")
likes_count = models.PositiveIntegerField(default=0) # denormalized counter
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
tags = TaggableManager(blank=True)
class Meta:
ordering = ["-created_at"]
indexes = [
models.Index(fields=["created_at"]),
models.Index(fields=["user"]),
]Notes:
likes_countis maintained in code (signals/service layer) as a denormalized counter.tagsrequires django‑taggit; run migrations after enabling the app.- Images are user uploads. For demo fixtures, we copy seed images from
static/tomedia/(see below).
Make sure these are in pyproject.toml (or requirements.txt):
Django>=5djangorestframeworkdrf-spectacular(optional, for/api/docs)django-allauthdjango-taggitPillowpsycopg2-binary(orpsycopg[binary]when using psycopg3)
Create .env from .env.example:
## test secret key for quick launch
SECRET_KEY=django-insecure-8z&v%h6@p_c7!zq^m8y4$w2u1r0t9q3f5k1n7b4e0d6g2j8l5
DJANGO_DEBUG=1
POSTGRES_DB=chattym
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
DB_HOST=db
DB_PORT=5432
ALLOWED_HOSTS=*
EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
# S3/MinIO (optional)
USE_S3=0
MINIO_ENDPOINT=
MINIO_ACCESS_KEY=
MINIO_SECRET_KEY=
MINIO_BUCKET=
Media configuration (defaults in settings):
MEDIA_URL=/media/
MEDIA_ROOT=/app/media
STATIC_URL=/static/
STATIC_ROOT=/app/staticfiles
Project includes Dockerfile and docker-compose.yml.
# build and run
docker compose up --buildThe entrypoint waits for DB, runs migrate, optional superuser creation (via DJANGO_SUPERUSER_EMAIL/DJANGO_SUPERUSER_PASSWORD), collectstatic, then launches the dev server.
Default admin (if present in fixtures):
admin@users.com
TestUser#2025
All seed users share the same password for convenience in local dev.
docker compose run --rm --entrypoint "" web python manage.py loaddata fixtures/users_fixture.json fixtures/users_emails_fixture.json fixtures/posts_fixture.json fixtures/comments_fixture.jsonpoetry install
poetry run python manage.py migrate
poetry run python manage.py runserverUseful:
poetry run python manage.py loaddata fixtures/users_fixture.json
poetry run pytest -q- Prometheus — metrics collection and storage
- Grafana — visualization and dashboards
- Alertmanager — alert routing and notifications
- django-prometheus — Django application metrics
- node_exporter — host-level metrics (CPU, RAM, disk, network)
- cAdvisor — Docker container metrics
- blackbox-exporter — external HTTP endpoint probing
All services run in a shared Docker network and are orchestrated via Docker Compose.
docker compose \
-f docker-compose.yml \
-f monitoring/docker-compose.monitoring.yml \
up --builddocker compose \
-f docker-compose.yml \
-f monitoring/docker-compose.monitoring.yml \
down && \
docker network rm chattym_monitoring chattym_default 2>/dev/null || true && \
docker compose \
-f docker-compose.yml \
-f monitoring/docker-compose.monitoring.yml \
up --build| Service | URL |
|---|---|
| Django App | http://localhost:8000 |
| Prometheus | http://localhost:9090 |
| Grafana | http://localhost:3000 |
| Alertmanager | http://localhost:9093 |
You can import ready-to-use dashboards from Grafana Marketplace:
- Node Exporter Full — 1860
- cAdvisor — 14282
- Blackbox Exporter — 7587
- Django / Python Metrics — 7990, 17868
Alerting rules are defined in:
monitoring/prometheus/alert_rules.yml
Alertmanager is configured and running. Currently, alerts are routed to a placeholder receiver (dev-null). The setup is ready for future integrations:
- Telegram
- Slack
- Email (SMTP)
- Webhooks
Prometheus collects metrics from:
- Django application
- endpoint: /metrics
- request latency, status codes, DB queries, exceptions
- Node Exporter
- CPU, memory, disk, filesystem, network
- cAdvisor
- container CPU/memory usage
- restart counts
- container lifecycle
- Blackbox Exporter
- HTTP availability checks (e.g.
https://google.com)
You can verify targets here:
http://localhost:9090/targets
All targets should be in UP state.
✔ Monitoring stack is fully operational
✔ Metrics collection verified
✔ Ready for dashboards and alerting extensions
When drf-spectacular is enabled:
- OpenAPI JSON:
/api/schema/ - Swagger UI:
/api/docs/
Posts API (examples):
# list posts
curl -s http://localhost:8000/api/posts/
# search by text/title
curl -s "http://localhost:8000/api/posts/?search=django"
# create with tags and optional image
curl -s -X POST http://localhost:8000/api/posts/ -F "title=Hello" -F "text=World" -F "tags=django,chattym" -F "image=@/path/to/file.jpg"Common query params: ?search=, ?ordering=, ?user=, ?active=1, ?q=.
The project uses Pytest and runs tests inside Docker to ensure a consistent environment (Python, dependencies, and PostgreSQL).
# clean start (app only) + run tests
docker compose down --remove-orphans -v \
&& docker network prune -f \
&& docker compose build --no-cache \
&& docker compose up -d --build \
&& docker compose exec web sh -lc "poetry run pytest -v"Note:
- Tests are executed inside the web container.
- Volumes are removed (-v), so the database is reset (expected for tests).
- Images 404 in dev → copy seed images (
static/… → media/…, see above). VerifyMEDIA_URL=/media/and dev server serves media inurls.py. - Tagging fails → ensure
django-taggitis inINSTALLED_APPS, runmakemigrations/migrate. - Auth emails not received → dev uses console backend; switch to SMTP in
.envfor real emails. - DB issues in Docker →
docker compose down -vto clear volumes, thenup --build. - Swagger missing → install/enable
drf-spectacularand include schema URLs inurls.py.
apps/— users, posts, comments, likes, follows, messaging, notificationsconfig/— settings & urlsdocker/entrypoint.sh— boot logic for containersfixtures/— demo datastatic/,templates/— client assets and templates
-
One-command service startup via Docker Compose (
docker compose up --build) -
Comprehensive container init script (
docker/entrypoint.sh) -
Fixture set for fast, end-to-end service testing (
fixtures/) -
Hide the admin URL in urls via .env
-
Auth via Google (OAuth2)
-
Grafana + Prometheus + Alertmanager integration
-
Auth protected with CAPTCHA (django-turnstile)
-
CI for tests/linters (flake8)
-
Snowfall visual effect for the UI (with switcher)
-
Test coverage of the service
Author: Maksym Petrykin
Email: m.petrykin@gmx.de
Telegram: @max_p95