Skip to content

maciejb2k/silent-dose

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Silent Dose

A simple Ruby on Rails app for tracking supplement intake, generating daily reports, and sending notifications to help users stay on top of their health routines. With a mobile-friendly interface and automatic daily summaries, it makes supplement management easy and efficient.

I am using this app by myself, and in my free time I am actively working on this project.

Rails Ruby Hotwire Postgres Redis Docker

alt text

Technologies

Ruby 3.2.5, Rails 7.2, Hotwire, Docker, PostgreSQL, Redis, Sidekiq, Devise, Pundit, ActiveAdmin.

Features

  • Supplement Database: A comprehensive list of supplements to be tracked.
  • Daily Report Generation: Automatically creates a report at the start of each day.
  • Customizable Report Template: Users can customize a report template from which daily reports are generated.
  • Automatic Daily Reports: The app automatically creates a daily report for each user at the start of the day.
  • Email Notifications: Sends email notifications about supplements already taken and those still pending.
  • Morning Summary: Sends a summary email of the previous day’s supplement intake.
  • Mobile-Friendly Interface: Simple, Bootstrap-based interface for mobile use, allowing users to check off supplements taken.
  • Background Jobs: Handles background tasks like sending notifications and generating reports.
  • Hotwire Integration: Uses Rails Hotwire for a responsive front-end experience.
  • Admin Panel: Built-in admin panel for managing app data and users.

Development

Install required Ruby version, I am using chruby and ruby-install.

Install gems:

bundle install

Run the development docker compose:

docker compose up -d --remove-orphans

Copy .env.development.template to .env.development and fill in the values.

Create the database, run the migrations and seed the database:

rails db:reset

# or

rails db:create
rails db:migrate
rails db:seed

Start the application:

./bin/dev

To create a demo user with credentials demo@silentdose.com:password, run the following command. If the user already exists, it will delete the user and recreate it:

rake db:create_demo_user

Deploying to production with Docker Compose

I created and successfully deployed this application for personal use, and I will share the steps I took to deploy it—it's not difficult.

VPS

Purchase any VPS server of your choice (Hetzner, DigitalOcean Droplet, etc.). In my case it was Hetzner Shared vCPU CCX23 (2 vCPU / 4GB RAM / 40GB SSD) with Ubuntu 24.04.1 LTS. Setup login with SSH keys.

ZSH

Install ZSH and Oh My Zsh:

# Install ZSH
sudo apt install zsh
chsh -s $(which zsh)

# Relogin to apply the changes and verify the shell
echo $SHELL
$SHELL --version

# Install Oh My Zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Docker

Install Docker:

# Uninstall all conflicting packages:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done

# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# Add the repository to Apt sources:
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update

# Install Docker:
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

UFW Firewall

Install and configure UFW:

sudo apt install ufw
sudo ufw app list
sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status

CloudFlare

Login to CloudFlare (I am using it for DNS and SSL - but you can use any other service):

  • Create in CloudFlare DNS a new A record with the server IP address.
  • Enable Strict SSL/TLS encryption mode in CloudFlare.
  • Go to <domain name> > SSL/TLS > Origin Server > Create Certificate and copy the certificate and key.
# Copy the certificate from cloudflare
sudo nano /etc/ssl/cert.pem

# Copy the key from cloudflare
sudo nano /etc/ssl/key.pem

I am using a certificate from Cloudflare for HTTPS because I want to prevent exposing the domain to the public (though it might still be exposed, and I could be mistaken—please correct me if that's the case!), unlike when using Let's Encrypt with Certbot.

Nginx Reverse Proxy

Install and configure Nginx:

sudo apt install nginx

Create a new file /etc/nginx/sites-available/silent-dose with the following content, replace example.com with your domain name.

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    ssl_certificate         /etc/ssl/cert.pem;
    ssl_certificate_key     /etc/ssl/key.pem;

    server_name example.com www.example.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Configure Nginx:

# Remove the default configuration
rm /etc/nginx/sites-available/default
rm /etc/nginx/sites-enabled/default

# Test the configuration
sudo nginx -t

# Enable the new configuration
ln -s /etc/nginx/sites-available/silent-dose /etc/nginx/sites-enabled/

# Reload Nginx
sudo systemctl reload nginx

# Check the status
sudo systemctl status nginx

Application setup

Clone the repository with the application.

Copy .env.production.template to .env.production and fill in the values.

Create the database:

docker compose -f docker-compose.prod.yml up -d db
docker compose -f docker-compose.prod.yml exec -it db bash
psql -U postgres
CREATE DATABASE "silent-dose_production";
docker compose -f docker-compose.prod.yml down

Start the application:

docker compose -f docker-compose.prod.yml build
docker compose -f docker-compose.prod.yml up -d --remove-orphans

Stop the application:

docker compose -f docker-compose.prod.yml down

With every new version of the application, you have to rebuild the image and restart the container.

git pull
docker compose -f docker-compose.prod.yml up -d --remove-orphans --build

Configure appropriate timezone in the system and in the .env.production file, to make sure that cron on OS and sidekiq-cron in the application are in sync:

timedatectl
timedatectl set-timezone Europe/Warsaw

Backup and Restore the Database

Manual Backup and Restore

To backup the database, use the following command on the running container:

docker compose -f docker-compose.prod.yml exec -it db pg_dump -U postgres silent-dose_production > pgdump-$(date +%F_%H-%M-%S).dump

To restore the database, use the following commands on the running container:

# Terminate all connections to the database, to make drop possible
docker compose exec -it db psql -U postgres -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'silent-dose_production' AND pid != pg_backend_pid() AND leader_pid IS NULL;"
# Drop the database, must be in a separate command, because DROP DATABASE cannot be executed in a transaction block
docker compose exec -it db psql -U postgres -c "DROP DATABASE IF EXISTS \"silent-dose_production\";"
# Create a new database
docker compose exec -it db psql -U postgres -c "CREATE DATABASE \"silent-dose_production\" ENCODING UTF8;"
# Restore the database from the dump
docker compose -f docker-compose.prod.yml exec -T db bash -c "pg_restore -U postgres -v -d silent-dose_production" < pgdump.dump

Backup and Restore

You can also use the ./db_backup.sh and ./db_restore.sh scripts to backup and restore the database.

If the scripts are not executable, make them executable:

chmod +x backup.sh restore.sh

Backup with db_backup.sh to current location:

./db_backup.sh

Backup with db_backup.sh to a specific location:

./db_backup.sh /path/to/backup
./db_backup.sh /backups
./db_backup.sh ..

Restore with db_restore.sh without arguments and with prompt:

./db_restore.sh

Restore with db_restore.sh using arguments:

./db_restore.sh my_database /path/to/backup-file.dump

Automatic Database Backup with Cron

Install cron:

sudo apt update cron
sudo apt install cron

Check if cron is running:

sudo systemctl restart cron
sudo systemctl status cron

Create a backup directory:

mkdir /home/app/silent-dose_backups

Make db_backup.sh executable:

chmod +x db_backup.sh

Edit the crontab:

crontab -e

Add this line at the end of the file to backup the database every day at midnight (change the paths to match your setup):

0 0 * * * /home/app/silent-dose/db_backup.sh /home/app/silent-dose_backups

Verify content of the crontab:

crontab -l

The crontab will now automatically backup the database every day at midnight. Verify the backups:

ll /home/app/silent-dose_backups

About

App for tracking dietary supplement intake

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published