Daily Milk Delivery Calculator - Multi-tenant SaaS on Railway
abhishekmitra-ait
FREEOP

6 months ago

What I Built: A full-stack Flask application that tracks daily milk deliveries with automated billing calculations. Started as a simple tracker, evolved into a multi-tenant SaaS with user authentication, OAuth integration, and personalized settings.

Live: https://web-production-01a84.up.railway.app/

The Journey:

v1.0 - MVP (SQLite + Basic CRUD)

  • Simple Flask app with local SQLite
  • Deployed using Railway's GitHub integration
  • Challenge: Database persistence across deployments
  • Solution: Discovered Railway Volumes for persistent storage

v2.0 - Production Database Migration (SQLite → PostgreSQL)

  • Hit SQLite's concurrency limits with multiple users
  • Migrated to Railway's PostgreSQL in one click
  • Challenge: Auto-increment sequences broke after data migration
  • Solution: Created custom migration script to reset PostgreSQL sequences

v3.0 - Multi-User with Authentication

  • Added OAuth (Google + GitHub) using Authlib
  • Implemented email verification with custom token system
  • Challenge: OAuth callbacks failing in production (http vs https)
  • Solution: Dynamic redirect URI fixing:

v4.0 - User-Specific Data Isolation

  • Added foreign keys linking records to users
  • Challenge: Existing data had no user association
  • Solution: Smart migration script that assigns orphaned records to primary user

v5.0 - Personalized Settings

  • Per-user currency (10+ currencies) and milk pricing
  • Auto-calculation with user-defined rates
  • Optional bulk recalculation of historical records
  • Challenge: Column additions without downtime
  • Solution: Auto-migration on startup:

Railway Features I Love:

  1. Zero-Config PostgreSQL: One-click database provisioning with automatic DATABASE_URL injection
  2. Environment Variables: Seamless secret management across dev/prod
  3. Volume Persistence: Used for backup storage before PostgreSQL migration
  4. Automatic HTTPS: No SSL certificate headaches
  5. GitHub Integration: Push to deploy - Railway handles the rest

Technical Highlights:

Smart Database Detection:

Automatic Schema Migrations: Instead of complex migration tools, implemented auto-detection and migration on startup - perfect for Railway's ephemeral deployments.

Session-Based Multi-Currency: Each user sees their own currency symbol throughout the app - achieved with user settings stored in PostgreSQL.

Architecture:

  • Backend: Flask + SQLAlchemy ORM
  • Database: Railway PostgreSQL with connection pooling
  • Auth: OAuth 2.0 (Google/GitHub) + custom email verification
  • Frontend: Jinja2 templates with responsive CSS
  • Deployment: Gunicorn WSGI server on Railway

What I Learned:

  1. Railway's DATABASE_URL uses postgres:// but SQLAlchemy expects postgresql:// - quick fix avoided hours of debugging
  2. PostgreSQL sequences need manual reset after bulk imports
  3. Railway's environment variable injection makes 12-factor apps trivial
  4. Connection pooling is essential for Railway's PostgreSQL (pool_pre_ping, pool_recycle)
  5. Auto-migrations on startup work better than separate migration scripts for small apps

Challenges Overcome:

  • 404 errors post-deployment: Fixed with proper _external=True in url_for()
  • OAuth state mismatch: Railway's HTTPS enforcement required callback URL fixes
  • Data migration: Custom scripts handled SQLite boolean (0/1) to PostgreSQL boolean conversion

What's Next:

  • CSV export functionality
  • REST API for mobile apps
  • Scheduled email reports using Railway Cron Jobs

Railway made deployment so smooth that I spent more time on features than DevOps. The PostgreSQL integration alone saved days of setup work. This project went from "weekend hack" to "production SaaS" thanks to Railway's simplicity!

Attachments

0 Replies

Welcome!

Sign in to your Railway account to join the conversation.

Loading...