Case Study 38-2: Maya Deploys — The Arc Completes

The Morning of the Deployment

Maya Reyes set her alarm for 6:30 a.m. on a Wednesday in November. Not because the deployment required it — Render's process is automated and she could do it at any time. She set the alarm because she wanted to be awake and present for it.

This was the thing she had been building toward, in one form or another, since she first opened a Python file in Chapter 1.

She made coffee. She sat at her desk. She pushed the commit.

git push origin main

What She Had Built

Before walking through the deployment, let's take inventory of what Maya was deploying.

The database: maya_projects.db — a SQLite database that had evolved since Chapter 23. It contained: - 11 active project records - 847 time entries spanning 18 months - 73 milestone records across all active projects - Invoice history for all completed and active projects

The application: A Flask app with six routes: - / — project code entry (login) - /status — the live project status page (protected by session) - /logout — clears the session - /admin/projects — Maya's private view of all projects (protected by admin password) - /admin/time-entry — add time entries without opening a database editor - /404 — custom error page

The data: The same CSV and database structure she had been building since Chapter 9, now organized into a proper relational schema.

The automation: Scheduled invoice generation still ran via the cron jobs set up in Chapter 22 — those were separate scripts that wrote to the database. The portal was read-only from the client's perspective.


The Deployment Process

Maya had tested the Dockerfile locally the evening before. The build took 94 seconds — longer than Priya's because her database and some dependencies were larger.

# Local test (evening before deployment)
docker build -t maya-portal .
docker run -p 8000:8000 --env-file .env maya-portal
# Opened http://localhost:8000 — tested all six routes
# Entered GRBN-2024-002 (Kevin's project code) — status page loaded correctly
# Verified database was accessible inside the container

The critical configuration for Maya's deployment was the persistent disk. Her database was her business. If it disappeared, she would lose months of time entries, all milestone data, and the complete history of every project.

Render configuration:

Setting Value Why
Instance Type Starter ($7/month) Always-on — clients shouldn't get cold-start delays
Persistent Disk Mount /app/data (1GB, $1/month) SQLite database lives here
SECRET_KEY 64-char hex string Signs session cookies
DATABASE_PATH /app/data/maya_projects.db Explicit path for production
ADMIN_PASSWORD Strong password from 1Password Maya's admin section
FLASK_DEBUG false Always false in production

Total cost: $8/month.

For context: the portal effectively replaced the status email traffic between Maya and her clients — approximately three to four emails per client per week, multiplied by eight clients. At Maya's consulting rate of $175/hour, even a conservative estimate of 30 minutes of email time saved per week was worth $87.50 per week. The $8/month infrastructure cost was noise.


The Database Migration Problem

Maya hit one issue she had not anticipated: her SQLite database was on her laptop. The Render server had an empty persistent disk.

She needed to seed the production database with her existing data before the portal went live.

Option 1: Copy the SQLite file to the Render server via the CLI. Option 2: Run a migration script from her laptop that reads from the local database and inserts into the production database. Option 3: For a SQLite file, copy the .db file directly via Render's shell access.

She chose Option 3 — it was simplest and least error-prone. Render provides shell access to running services:

# From Render's shell access
# (render.com → your service → Shell)

# Verify the persistent disk is mounted
ls /app/data
# Output: (empty — new disk)

# Use Render's file upload or rsync to transfer the database
# Maya used Render's Web Shell "upload file" feature to transfer maya_projects.db

After the transfer:

# Inside the Render shell, verify the database is intact
python3 -c "import sqlite3; conn = sqlite3.connect('/app/data/maya_projects.db'); print(conn.execute('SELECT COUNT(*) FROM projects').fetchone())"
# Output: (11,)

Eleven project records. The database was intact.

Note for readers: This manual migration step is common in initial deployments. If you are starting a new project from scratch on Render, the persistent disk starts empty, which is fine — your application creates the database on first run. Maya's situation (migrating an existing database) required this extra step.


The First Deployment

The Render build log:

==> Cloning from https://github.com/maya-reyes/client-portal
==> Building Docker image
[+] Building 94.1s (12/12) FINISHED
==> Running health check...
==> Health check passed
==> Deploy succeeded
==> Your service is live at: https://portal.mayareyes.consulting

Maya had configured a custom domain (portal.mayareyes.consulting) through Render's domain settings and her DNS provider (Namecheap). Render provided the SSL certificate automatically via Let's Encrypt.

For $8/month, she had: - A professionally deployed web application - A custom domain (portal.mayareyes.consulting) - SSL/HTTPS enabled (the padlock in the browser) - Always-on hosting - Persistent SQLite database - Automatic deployments on git push


Kevin's First Login

Maya sent Kevin from GreenBridge Logistics an email at 9:17 a.m., two hours after the deployment completed:

Kevin — the portal you've been using locally is now live at portal.mayareyes.consulting. Your project code is still GRBN-2024-002.

A few things worth knowing: - The URL works from any device — phone, tablet, computer - It's secured with HTTPS (you'll see the padlock in your browser) - The status page updates in real time as I log hours and complete milestones

Let me know if you have any questions or if anything looks off.

— Maya

Kevin's reply came at 9:41 a.m. He had been in a meeting. He replied from his phone:

Just checked this from my phone during the meeting break. This is excellent — I can see we're at 71% of hours. Let's talk about scope before we hit 80%. Can we schedule 30 minutes this week?

Maya stared at that reply for a moment.

Kevin had seen the budget status without asking her for it. He had made a proactive business decision based on that information. And the conversation that followed — a scope discussion rather than a "where do we stand" status request — was more valuable than anything she could have sent in an email.

The portal had done exactly what she designed it to do.


The Full Rollout

Maya sent portal access codes to all eight active clients over the following two days. Responses varied:

Natalie (Hartwell Financial): "I'm going to share this with our CFO. She has been asking for project status every week." (Maya had not considered that clients might share access internally — she quickly added a note in the project code email that the code could be shared with the client's internal stakeholders.)

Kevin (GreenBridge): Already using it. Had checked it four times since the initial login.

The Coastal Property Management team: "This is very clean. Can you add a column for invoices?" (Feature request logged.)

Two clients: No response within a week — Maya followed up via phone. Both said they had not had time to try it yet but would. Neither had any objections to the portal itself.

Two clients with completed projects: Maya sent them archive links showing their project history. They could see the final timeline, total hours, and milestone completion dates. One client used this as supporting documentation in an internal report.


What Maya Learned About Deployment

The database is the critical asset

For web applications that write data, the database is more important than the application code. The code can be redeployed in minutes. The data cannot be reconstructed if lost. Maya set up a daily backup Lambda function (Chapter 22 patterns applied to a new use case):

# lambda_backup.py
# Runs daily at 2 AM via EventBridge
# Copies maya_projects.db from Render persistent disk to S3

import boto3
import subprocess
from datetime import date

def lambda_handler(event, context):
    # Download the database from the Render persistent disk via SFTP/SCP
    # (Render shell access supports SCP with the right SSH key setup)
    today = date.today().isoformat()
    backup_key = f"backups/maya_projects_{today}.db"

    s3 = boto3.client("s3")
    s3.upload_file(
        "/tmp/maya_projects.db",
        "maya-consulting-backups",
        backup_key,
    )
    return {"status": "backup complete", "key": backup_key}

The backup solution was imperfect (the download step required coordination with Render's infrastructure that took a day to configure), but having it in place before the portal had real client data was the right priority.

Custom domains are worth the setup time

portal.mayareyes.consulting conveyed professionalism that maya-portal.onrender.com did not. The DNS configuration took thirty minutes. Render handled the SSL certificate automatically. The total investment was thirty minutes and $12/year for the subdomain via Namecheap. Worth it.

Production behavior differs from development behavior

Two issues Maya encountered after launch that had not appeared in local testing:

  1. Session expiry: On her laptop, she tested with the browser always open. In production, clients occasionally reported being sent to the login page unexpectedly. The issue: session.permanent = False (the Flask default) expires sessions when the browser closes. Clients closing their laptop lids between sessions triggered this. She set session.permanent = True and app.permanent_session_lifetime = timedelta(days=7).

  2. Timezone display: Time entries logged on Maya's laptop (Pacific Time) displayed in UTC on the portal. Clients in Eastern and Central time zones found the dates confusing. Maya added timezone handling: all timestamps stored as UTC in the database, converted to the client's local timezone for display using a timezone field in the project record.

Neither issue was serious. Both would have been caught by a more thorough test suite. Maya added them to her testing checklist for future applications.

Deployment is a skill worth investing in

Before this project, Maya had always thought of deployment as something "technical people" handled. The process of building the Dockerfile, configuring Render, troubleshooting the database migration, and setting up DNS demystified it completely.

Deployment is not magic. It is a sequence of concrete, learnable steps. The same discipline that made her a competent Python developer made her a competent deployer: read the documentation, test systematically, and understand the error messages.


The Complete Portfolio

Maya Reyes, November 2024:

Tool Chapter Status
Automated project tracking CSV → database 9, 23 Running
Excel invoice generation 16 Running
Monthly automated invoice emails 19 Running
Scheduled monthly report pipeline 22 Running
PDF client status reports 36 Running
Client-facing project status portal 37 Running
Production deployment with HTTPS 38 Running
Daily database backup to S3 38 Running

Total monthly infrastructure cost: $8 (Render Starter + Render Disk) Time saved per month vs. manual processes: approximately 12 hours At $175/hour: approximately $2,100/month in recovered billable capacity

This is not a hypothetical ROI calculation. It is an approximation of real time that Maya was previously spending on administrative work — generating invoices, responding to status emails, formatting reports — and is now spending on consulting work, or on her own time.

The automation she built across this book is not a portfolio of academic exercises. It is infrastructure that runs her business.


What Comes Next

Maya's Chapter 38 milestone is not an ending. It is a foundation.

The things she can now build that she could not build at Chapter 1: - A scheduling integration that lets clients request consultations through the portal - An analytics dashboard showing her own business trends (utilization rate, revenue by client, hours by project type) - ML-based project estimation using her 18 months of historical time data - An API that her clients' internal systems can query for project status

The tools are the same ones she has been building across this book. The scope of what is possible has expanded.

Chapter 39 covers the practices that make this work sustainable: testing, version control discipline, documentation, and collaboration patterns. The tools work. Chapter 39 is about making sure they keep working.

Chapter 40 covers the portfolio itself — how to present what you have built to colleagues, clients, and future employers, and where to go from here.


A Note on the Arc

Maya started this book tracking projects in a spreadsheet and ending every month manually generating invoices in Word.

She ends this book with: - A production web application that her clients use - Automated infrastructure that runs without her intervention - Eight months of time entries, milestones, and business data in a structured database - A technical skill set that has measurably changed what her consulting practice can do

None of this required a computer science degree. It required curiosity, patience, and the willingness to break things in a local development environment before deploying them to production.

That is the real argument for Python in business. Not that it makes you a developer. That it makes you someone who can build the tools your business needs, instead of waiting for someone else to build them.


The arc is not complete. It is just beginning. What you build next is up to you.