Beerdegu is a real-time web application meant for beer tasting sessions, when you and your friends are rating every consumed beer (color, smell, taste etc.).
Built with Django Channels, Django Rest Framework, Postgres, Redis in a Dockerized environment with an option to deploy to Railway.app, Fly.io or Heroku.com.
This setup has been tested with Python 3.10 and Node 16.
- Django 4.2 + Django Rest Framework :
django
djangorestframework
- Django Channels 4 :
channels
- handling websockets backend django-extensions
- django utilitiesdjango-cors-headers
- handling cross-origin requestsdjango-filter
- filter backend for drf viewsdjango-q
- async task queuedjango-import-export
- data import/export in admin paneldjango-allauth
,dj-rest-auth
,djangorestframework-simplejwt
- authentication (jwt, google)django-sesame
- websockets token authenticationopenpyxl
- excel reports generationdrf-spectacular
- OpenAPI schema generationcoverage
- for code coverage reports and running unit testsmypy
+djangorestframework-stubs
- for better typing experiencepsycopg2
- needed to use Postgres (in Docker container)channels_redis
,redis
- connection to Redis database servicewhitenoise
- collecting and serving static files (if not using AWS S3)boto3
,django-storages
- storing static and media files on AWS S3daphne
- production asgi server
Frontend has been rewritten and moved into separate repository.
- React 18
- Typescript
react-use-websocket
- websocket client, connects with ws backend@mui/material
,@mui/icons-material
,@mui/lab
, - Material UI librarysass
- enables scss/sass supportaxios
- http client@tanstack/react-query
- client-side data fetching and cachingreact-infinite-scroll-component
- infinite scrollreact-toastify
- toast notificationsvitest
,@testing-library/react
+ other packages - unit testingmsw
- mocking http requests in tests
Create a virtual environment from cmd (or do it in Pycharm manually)
cd backend
python -m pip install --upgrade pip
pipenv install
pipenv shell
Run django application from cmd (or add new Django configuration if using Pycharm)
python manage.py runserver
Preparing (if there are any changes to db schema) and running migrations
python manage.py makemigrations
python manage.py migrate
Create superuser
python manage.py createsuper user
You need to provide VITE_WEBSOCKET_URL
and VITE_BACKEND_URL
environment variables.
Install node dependencies.
cd frontend
yarn install
Run development server in second terminal
yarn dev
cd backend
Run tests using Coverage instead of python manage.py test
coverage run manage.py test
Get report from coverage:
coverage report -m
First create env
folder in root directory with following env files:
env/postgres.env
# credentials to postgres database
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=postgres
env/backend.env
DJANGO_SETTINGS_MODULE=core.settings.dev
SECRET_KEY=...
# same values as in postgres.env
DB_NAME=postgres
DB_USER=postgres
DB_PASSWORD=postgres
# same as in docker-compose.yml
DB_HOST=postgres_db
DB_PORT=5432
# same as in docker-compose.yml
REDIS_HOST=redis_db
REDIS_PORT=6379
# if you want to use mailing functionality e.g with smtp backend
EMAIL_HOST=...
EMAIL_PORT=...
EMAIL_USER=...
EMAIL_PASSWORD=...
# Google auth - configured in Google Cloud Platform
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GOOGLE_CLIENT_REDIRECT_URI=...
# Site object's name in Django admin - needed for building links to frontend
# e.g. when sending email with password reset link or activation link
FRONTEND_SITE_NAME=beerdegu
# (Optional) If you want to test upload to AWS S3
USE_AWS_S3=True
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_STORAGE_BUCKET_NAME=...
env/redis.env
TZ=Europe/Warsaw
env/frontend.env
# required for hot reloading to work in docker
CHOKIDAR_USEPOLLING=true
WATCHPACK_POLLING=true
NODE_ENV=development
# in format: PROTOCOL://HOST:PORT without trailing slash!
# variable names have to be prefixed with VITE_
VITE_WEBSOCKET_URL=ws://127.0.0.1:8000
VITE_BACKEND_URL=http://127.0.0.1:8000
Make sure Docker Engine is running.
While in root directory, build docker images and run them with docker-compose. This might take up to few minutes. Rebuilding image is crucial after installing new packages via pip or npm.
docker-compose up --build
Application should be up and running: backend 127.0.0.1:8000
, frontend 127.0.0.1:3000
.
If images had been installed and no additional packages have been installed, just run to start containers:
docker-compose up
Bringing down containers with optional -v flag removes all attached volumes and invalidates caches.
docker-compose down
To run commands in active container:
docker exec -it CONTAINER_ID bash
Rebuilding individual containers instead of all of them
docker-compose build CONTAINER_NAME
If there are problems caused by caching, then you can use optional flag to build container without Docker's cache
docker-compose build CONTAINER_NAME --no-cache
Add your local ip4 address to existing ALLOWED_HOSTS
list in backend/core/settings/dev.py
file.
You can retrieve it by running ipconfig
in terminal and looking for IPv4 Address
.
ALLOWED_HOSTS = ["backend", "localhost", "127.0.0.1", "YOUR_IP_ADDRESS"]
Go to https://railway.app/dashboard and create a new project with Deploy from GitHub repo
.
Create backend, django_q, postgres and redis services in production environment by right-clicking on project's canvas.
Configure automatic deployments from a chosen branch.
Add New Service
> GitHub Repo
Set RAILWAY_DOCKERFILE_PATH
variable to Dockerfile.api
(or Dockerfile.fly
if you want to use old frontend).
RAILWAY_DOCKERFILE_PATH=Dockerfile.api
PRODUCTION_HOST=<appname>.up.railway.app
DJANGO_SETTINGS_MODULE=core.settings.prod
FRONTEND_SITE_NAME=Beerdegu
PORT=8000
SECRET_KEY=...
CORS_ORIGIN_WHITELIST=...
CORS_ORIGIN_REGEX_WHITELIST=...
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
GOOGLE_CLIENT_REDIRECT_URI=...
USE_AWS_S3=True
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_STORAGE_BUCKET_NAME=...
If using old frontend, also add VITE_BACKEND_URL
, VITE_WEBSOCKET_URL
, SERVE_FRONTEND
variables.
Set Start command
in Deploy settings section to daphne -b 0.0.0.0 -p 8000 core.asgi:application -v2
Add New Service
> GitHub Repo
Set RAILWAY_DOCKERFILE_PATH
to Dockerfile.api
.
Add PRODUCTION_HOST
, SECRET_KEY
, DJANGO_SETTINGS_MODULE
, FRONTEND_SITE_NAME
variables.
Set Start command
in Deploy settings section to python manage.py qcluster
.
Add New Service > Database > Add Postgres
Copy DATABASE_URL
from Connect tab and put in shared variables.
Go into backend
directory and run railway run python manage.py migrate
to apply migrations.
Add New Service > Database > Add Redis
Copy REDIS_URL
from Connect tab and put in shared variables.
Settings
> Shared Variables
> production
Set DATABASE_URL
by coping DATABASE_URL from postgres service variables.
Set REDIS_URL
by coping REDIS_URL from redis service variables.
Set EMAIL_HOST
, EMAIL_PASSWORD
, EMAIL_PORT
, EMAIL_USER
variables.
Variables can also be referenced between services by using ${SERVICE_NAME.ENV_VAR_NAME}
syntax.
Launch a new app
fly launch
Set secrets: PRODUCTION_HOST
, SECRET_KEY
, REDIS_URL
, EMAIL_HOST
, EMAIL_PORT
, EMAIL_USER
, EMAIL_PASSWORD
,
GOOGLE_CLIENT_ID
, GOOGLE_CLIENT_SECRET
, GOOGLE_CLIENT_REDIRECT_URI
, FRONTEND_SITE_NAME
fly secrets set KEY=VALUE
Create postgres and redis addons
fly pg create
fly redis create
Attach postgres instance to the app (it will automatically set DATABASE_URL
env variable)
fly pg attach -a <postgres_app_name>
Deploy the app
Include VITE_BACKEND_URL
, VITE_WEBSOCKET_URL
build args to make frontend work
fly deploy --build-arg VITE_BACKEND_URL=https://beerdegu.fly.dev --build-arg VITE_WEBSOCKET_URL=wss://beerdegu.fly.dev
Connecting to app instance (e.g to create superuser)
fly ssh console
- Create Heroku Account
- Download/Install/Setup Heroku CLI
- After install, log into Heroku CLI:
heroku login
- After install, log into Heroku CLI:
- Run:
heroku create <app name>
to create the Heroku application - Set your environment variables for your production environment by running:
Or in the Heroku dashboard, go to Settings > Config Vars and add the variables there.
heroku config:set KEY=VALUE
Variables to set:DJANGO_SETTINGS_MODULE=core.settings.prod
DJANGO_SUPERUSER_EMAIL
,DJANGO_SUPERUSER_USERNAME
,DJANGO_SUPERUSER_PASSWORD
,PRODUCTION_HOST=<app name>.herokuapp.com
,SECRET_KEY
,EMAIL_HOST
,EMAIL_PORT
,EMAIL_USER
,EMAIL_PASSWORD
- Run:
heroku stack:set container
so Heroku knows this is a containerized application - Run:
heroku addons:create heroku-postgresql:hobby-dev
which creates the postgres add-on for Heroku - Run:
heroku addons:create heroku-redis:hobby-dev
which creates the redis add-on for Heroku - Deploy app by running:
git push heroku master
,
or manually in Heroku dashboard
or by pushing to your github repository, having Automatic Deploys set up - Go to
<app name>.herokuapp.com
to see the published website.
This repository uses Github Actions to run test pipeline.
tests.yml
- runs backend and frontend as separate jobs in one workflow