John: Week 5: Build Your Budget Tracker
Demo Day is three weeks out (April 29). You have the ambition and the ideas - now you need running code. Your budget tracker concept is strong, but today we're scoping to something you can build and demo in one session: add expenses and see a summary. Forecasting, trends, and security are real features - they come after you have a working app to build on top of.
Today's goal: walk out of class with a running Flask app - a home page, an expense form, and a summary page with totals. Everything else is a feature you stack on later.
Check In: What Are You Working On?
- Create a file called
TODO.mdin your project folder (right-click in the file explorer > New File) - Write one sentence about your plan for today. Example:
Build a working Flask app with an expense form and summary page.
- Save it (Cmd+S)
Part 1: Essential Catch-up
Fix favs.py - use your variables
Your favs.py defines variables but prints hardcoded strings instead of referencing them. Quick fix - this is the exact same f-string pattern you'll use in your Flask app.
Open favs.py and find lines like:
print("Drake")
Change them to use f-strings that reference your variables:
artist = "Drake"
print(f"My favorite artist is {artist}")
The {artist} part pulls the value from the variable instead of repeating the text. Do the same for any other hardcoded prints in the file.
Optional: v0-prompt.md and warmup.py templates are in your Week 4 guide if you want them. Not required today - the Flask app is the priority.
Part 2: Python Practice
Create a new file called practice.py.
Challenge: Build an expense report that stores expenses as variables, calculates totals, and prints a formatted summary showing how much budget you have left.
Your program should:
- Store a budget amount (like
500) as a variable - Store 3-4 expenses as separate variables with descriptive names (e.g.
rent,groceries,gas,subscriptions) - Calculate the total spent by adding all the expense variables together
- Calculate the remaining budget (budget minus total spent)
- Print a formatted expense report with borders, each expense listed with its dollar amount, the total, and the remaining balance
Example output (use your own numbers):
╔══════════════════════════════════════╗
Expense Report - John's Budget
──────────────────────────────────────
Budget: $500.00
──────────────────────────────────────
Rent: $200.00
Groceries: $85.50
Gas: $45.00
Subscriptions: $15.99
──────────────────────────────────────
Total Spent: $346.49
Remaining: $153.51
╚══════════════════════════════════════╝
Hints:
- Define each expense with a clear name:
rent = 200.00 - Add them up:
total = rent + groceries + gas + subscriptions - Use f-strings with formatting for dollar amounts:
f"${total:.2f}"gives you two decimal places - Build borders with
print("═" * 38)
Resources:
-
Variables - how to store text and numbers
-
Print Statements - how to display output, use f-strings, and format cards
Part 3: Build Your Budget Tracker
Time to build the real thing. You're creating a Flask app with three pages:
- Home - landing page for Budget Buddy
- Add Expense - form with description, amount, and category
- Summary - table of all expenses with a calculated total
Step 1: Install Flask
Open the terminal (View > Terminal) and run:
pip install flask
Use pip3 if pip doesn't work.
Step 2: Create app.py
Create a new file called app.py and paste this entire block:
from flask import Flask, request
app = Flask(__name__)
expenses = [
{"description": "Chipotle", "amount": 12.50, "category": "food"},
{"description": "Gas", "amount": 45.00, "category": "transport"},
{"description": "Spotify", "amount": 11.99, "category": "entertainment"},
]
@app.route("/")
def home():
return """
<html>
<head>
<meta charset="utf-8">
<title>Budget Buddy</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-slate-950 text-slate-100">
<div class="mx-auto max-w-2xl px-6 py-16">
<h1 class="text-4xl font-bold text-emerald-400">Budget Buddy</h1>
<p class="mt-4 text-lg text-slate-300">Track your spending. Know where your money goes.</p>
<div class="mt-10 flex flex-wrap gap-4">
<a class="rounded-lg bg-emerald-500 px-6 py-3 font-semibold text-slate-950 hover:bg-emerald-400" href="/add">Add Expense</a>
<a class="rounded-lg border border-emerald-500 px-6 py-3 font-semibold text-emerald-300 hover:bg-emerald-500/10" href="/summary">View Summary</a>
</div>
</div>
</body>
</html>
"""
@app.route("/add", methods=["GET", "POST"])
def add():
message = ""
if request.method == "POST":
description = request.form["description"]
amount = float(request.form["amount"])
category = request.form["category"]
expenses.append({
"description": description,
"amount": amount,
"category": category,
})
message = f'<p class="mb-4 rounded-lg bg-emerald-500/20 px-4 py-2 font-semibold text-emerald-300">Added: {description} (${amount:.2f})</p>'
return f"""
<html>
<head>
<meta charset="utf-8">
<title>Add Expense - Budget Buddy</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-slate-950 text-slate-100">
<div class="mx-auto max-w-2xl px-6 py-12">
<h1 class="text-2xl font-bold text-emerald-400">Add Expense</h1>
{message}
<form method="POST" class="mt-6 space-y-4 rounded-xl border border-slate-700 bg-slate-900/80 p-6">
<div>
<label class="block text-sm font-medium text-sky-300" for="description">What did you spend on?</label>
<input class="mt-1 w-full rounded-lg border border-slate-600 bg-slate-900 px-3 py-2 text-white placeholder-slate-500 focus:border-emerald-500 focus:outline-none" type="text" id="description" name="description" placeholder="e.g. Chipotle, gas, Netflix" required>
</div>
<div>
<label class="block text-sm font-medium text-sky-300" for="amount">How much? ($)</label>
<input class="mt-1 w-full rounded-lg border border-slate-600 bg-slate-900 px-3 py-2 text-white focus:border-emerald-500 focus:outline-none" type="number" id="amount" name="amount" step="0.01" min="0" placeholder="0.00" required>
</div>
<div>
<label class="block text-sm font-medium text-sky-300" for="category">Category</label>
<select class="mt-1 w-full rounded-lg border border-slate-600 bg-slate-900 px-3 py-2 text-white focus:border-emerald-500 focus:outline-none" id="category" name="category">
<option value="food">Food</option>
<option value="transport">Transport</option>
<option value="entertainment">Entertainment</option>
<option value="bills">Bills</option>
<option value="other">Other</option>
</select>
</div>
<button class="w-full rounded-lg bg-emerald-500 py-3 font-semibold text-slate-950 hover:bg-emerald-400" type="submit">Add Expense</button>
</form>
<p class="mt-8 text-sky-300"><a class="underline hover:text-white" href="/">Home</a> · <a class="underline hover:text-white" href="/summary">View Summary</a></p>
</div>
</body>
</html>
"""
@app.route("/summary")
def summary():
total = 0
rows = ""
for expense in expenses:
total = total + expense["amount"]
rows += f"""
<tr class="border-b border-slate-700">
<td class="px-4 py-3">{expense["description"]}</td>
<td class="px-4 py-3">${expense["amount"]:.2f}</td>
<td class="px-4 py-3 capitalize">{expense["category"]}</td>
</tr>
"""
if len(expenses) == 0:
rows = '<tr><td colspan="3" class="px-4 py-6 text-center text-slate-400">No expenses yet. <a class="text-sky-400 underline" href="/add">Add one.</a></td></tr>'
return f"""
<html>
<head>
<meta charset="utf-8">
<title>Summary - Budget Buddy</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-slate-950 text-slate-100">
<div class="mx-auto max-w-3xl px-6 py-12">
<h1 class="text-2xl font-bold text-emerald-400">Spending Summary</h1>
<div class="mt-6 overflow-hidden rounded-xl border border-slate-700">
<table class="w-full border-collapse text-left text-sm">
<thead class="bg-slate-900 text-sky-300">
<tr>
<th class="px-4 py-3">Description</th>
<th class="px-4 py-3">Amount</th>
<th class="px-4 py-3">Category</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-700">
{rows}
</tbody>
</table>
</div>
<p class="mt-6 text-xl font-bold text-emerald-400">Total: ${total:.2f}</p>
<p class="mt-8 text-sky-300"><a class="underline hover:text-white" href="/add">Add Expense</a> · <a class="underline hover:text-white" href="/">Home</a></p>
</div>
</body>
</html>
"""
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5000)
Here's what's going on:
-
expensesstarts with 3 example items so your summary page has data right away. Each expense is a dictionary - a set of key-value pairs like"description": "Chipotle". The whole list of dictionaries is your app's database for now (data resets when the server restarts, which is fine). -
/is the home page with links to Add and Summary. -
/addshows a form. When you submit it (POST), the code grabs the form data and appends a new dictionary to theexpenseslist. -
/summaryloops through every expense, builds a table row for each one, and adds up the total. -
Tailwind CSS loads from the CDN
<script>tag in each page's<head>.
Step 3: Run and test
- Save
app.py(Cmd+S) - Click the play button (top-right triangle)
- Open
http://localhost:5000in your browser (Codespaces: check the Ports tab) - Click View Summary - you should see the 3 example expenses and a total of $69.49
- Click Add Expense, fill in the form, submit it
- Go back to Summary - your new expense should appear with an updated total
To stop the server: click inside the terminal and press Ctrl+C.
Challenge: Add a budget limit
Near the top of app.py, right below expenses = [...], add a variable:
budget_limit = 500
Then on the summary page, right after the total line, add a line showing remaining balance:
<p class="mt-2 text-lg text-sky-300">Budget: ${budget_limit:.2f} | Remaining: ${budget_limit - total:.2f}</p>
If spending exceeds the budget, the remaining goes negative. That tells the user they're over budget.
Part 4: Save to GitHub
- Save all files (Cmd+S)
- Click the Source Control icon on the left sidebar
- Type a commit message:
add budget buddy flask app - Click Commit, then Sync Changes
Set Your Goal: Add a New Feature
Your app works. Now pick one feature to build before next week:
- Make expenses persist - save the list to a JSON file so data survives a server restart
- Category filter - add a dropdown on the summary page to filter expenses by category
- Trends page - create a
/trendsroute that shows which category you spend the most in
Use the AI chat to help you build it
-
Open the AI chat panel:
- Codespaces: Click the chat icon in the left sidebar, or press Ctrl+I
- Cursor: Press Cmd+L
-
Use this prompt template:
I'm building a budget tracker Flask app. This week I built the basic app with add/summary pages. Here's my current code: [paste your
app.py]. I want to add: [describe the feature you picked]. Can you help me understand what I need to change and guide me through it? Don't just give me the answer. Help me understand the steps.
- If something breaks, paste the error:
I got this error: [paste error]. What's wrong?
See the Prompting Cheat Sheet for more.
Update TODO.md
Open TODO.md and replace your sentence with the feature you picked. Be specific:
-
Good: "Save expenses to a JSON file so they persist between server restarts"
-
Not good: "work on my app"
Troubleshooting
"No module named flask"
Run pip install flask or pip3 install flask in the terminal.
Play button missing or doesn't run
Make sure app.py is the active file (click on its tab). Save it first (Cmd+S).
"Address already in use"
Click inside the terminal, press Ctrl+C to stop the old process, then run again.
Blank page or browser error
- File not saved - press Cmd+S
- Missing triple quotes (
""") around the HTML strings - Missing
@app.routedecorator above a function
Route shows "Not Found"
- Check the URL matches your
@app.route("/...")exactly - Make sure the route function is above the
if __name__block - Restart the app after making changes
Tailwind styles not showing
- Make sure
<script src="https://cdn.tailwindcss.com"></script>is in every page's<head> - Hard refresh the browser (Cmd+Shift+R)
Source Control issues
- Save all files first
- If there's no upstream branch, click "Publish Branch" when prompted
Still stuck
Ask the AI agent:
I'm building a budget tracker in Flask and I'm stuck on: [describe the problem]. Here's the error: [paste it]. What should I check?
Or ask your instructor.
Resources
- Flask - how routes, forms, and templates work
- Tailwind CSS - styling your app with utility classes
- GitHub Codespaces Guide - how to open and use Codespaces
- Cursor Guide - how to open and use Cursor
- GitHub Basics - how to commit and push your code
- Prompting Cheat Sheet - effective prompts for the AI agent