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 :
djangodjangorestframework - 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 shellRun django application from cmd (or add new Django configuration if using Pycharm)
python manage.py runserverPreparing (if there are any changes to db schema) and running migrations
python manage.py makemigrations
python manage.py migrateCreate superuser
python manage.py createsuper userYou need to provide VITE_WEBSOCKET_URL and VITE_BACKEND_URL environment variables.
Install node dependencies.
cd frontend
yarn installRun development server in second terminal
yarn devcd backendRun tests using Coverage instead of python manage.py test
coverage run manage.py testGet report from coverage:
coverage report -mFirst 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=postgresenv/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/Warsawenv/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:8000Make 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 --buildApplication 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 upBringing down containers with optional -v flag removes all attached volumes and invalidates caches.
docker-compose downTo run commands in active container:
docker exec -it CONTAINER_ID bashRebuilding individual containers instead of all of them
docker-compose build CONTAINER_NAMEIf 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-cacheAdd 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 launchSet 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=VALUECreate postgres and redis addons
fly pg createfly redis createAttach 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.devConnecting 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.prodDJANGO_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 containerso Heroku knows this is a containerized application - Run:
heroku addons:create heroku-postgresql:hobby-devwhich creates the postgres add-on for Heroku - Run:
heroku addons:create heroku-redis:hobby-devwhich 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.comto 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