> Source URL: /users/john-p/week-4.path
---
week: 4
date: 2026-04-01
---

# John: Week 4: Catch Up and Start Your Budget App

You want to build a serious budget tracker for Demo Day (April 29th). Right now your repo mostly has `favs.py` from Week 1. That is a normal starting point -- we just need **project documentation** for instructors, then a **first Flask version** of your app.

**Important:** A full budget product could include accounts, forecasting, and history. Your first Flask build is an **MVP**: add expenses and see a summary. It will look simpler than a fancy website on purpose. You are learning routes, forms, and Python lists. This guide uses **Tailwind CSS** via CDN so the UI still looks intentional. See [Tailwind CSS](../../resources/tailwind.resource.md).

---

## Check In: What Are You Working On?

Create `TODO.md` if you need it. Write one rough sentence -- for example: "Document my budget app idea and build a first Flask MVP." You will replace this with a sharper goal at the end.

- [ ] I have `TODO.md` with a rough sentence for today

---

## Part 1: Essential Project Catch-up

### Add `v0-prompt.md`

Create `v0-prompt.md` and describe your budget app in plain language (no leftover brackets). Example structure:

```markdown
You are my MVP build coach.

I am a high school student and a beginner programmer.
Use plain language. Define technical words in one sentence.

Project idea:
[Track spending, see totals, and eventually help me stay under a budget]

Target user:
[Me -- and anyone who wants a simple budget view]

Build me the smallest working MVP with only 3-5 must-have features.

Features:
1. [Add an expense with amount and category]
2. [See a list of expenses and a total]

Do not add extra features yet.
```

- [ ] I saved `v0-prompt.md` with my real details

### Add `vibe-code-report.md`

Use this outline (you do not have a v0 link yet -- that is OK):

```markdown
# Vibe Code Report

## Prototype Link

**No v0 link yet** -- I am building my first version in Flask.

## What I Plan to Build First

- Project idea (1-2 sentences):
- Platform: Flask first
- MVP features (3-5 bullets):

## Reflection

- How do you feel about the direction so far?
- What would you change with more time?
- What would you keep the same?

## Known limitations

- [What is not built yet]
```

- [ ] I filled every section of `vibe-code-report.md`

### Commit Part 1

1. Save all files
2. **Source Control** -- message: `add v0 prompt and vibe code report for budget app`
3. **Commit**, then **Sync Changes**

- [ ] I committed and synced

**Optional (not required):** Update `favs.py` to use **f-strings** with `{artist}` and `{song}` instead of hardcoded text in the prints -- good practice, but not required for your budget MVP. **Optional:** add `warmup.py` with a budget-themed formula.

---

## Part 2: Build Budget Buddy in Flask

Flask connects URLs to Python functions. This MVP stores expenses in a Python **list** in memory (they reset when the server restarts -- that is fine for Week 4). Styling uses **Tailwind**. See [Flask](../../resources/flask.resource.md).

### Step 1: Install Flask

Terminal (**View > Terminal**):

```bash
pip install flask
```

Use `pip3` if needed.

- [ ] Flask installed

### Step 2: Create `app.py`

Create `app.py` and paste:

```python
from flask import Flask, request

app = Flask(__name__)

expenses = []


@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-12">
            <h1 class="text-3xl font-bold text-emerald-400">Budget Buddy</h1>
            <p class="mt-3 text-slate-300">Track your spending. Know where your money goes.</p>
            <div class="mt-8 flex flex-wrap gap-3">
                <a class="rounded-lg bg-emerald-500 px-5 py-2 font-semibold text-slate-950 hover:bg-emerald-400" href="/add">Add Expense</a>
                <a class="rounded-lg border border-emerald-500 px-5 py-2 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="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> &middot; <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> &middot; <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)
```

Notes:

- **`expenses`** is a list of dictionaries -- your app's memory for now.
- **`/add` needs `methods=["GET", "POST"]`** so the form can submit.
- **Tailwind** -- keep the script tag in every page `<head>`.

- [ ] I created `app.py` and pasted the code

### Step 3: Run and test

1. Save `app.py`, click the **play button**
2. Open `http://localhost:5000` (Codespaces: **Ports** tab)

Add a few expenses, then open **View Summary**.

**Stop:** terminal focus, **Ctrl+C**.

- [ ] Home, Add, and Summary work
- [ ] Total updates after I add expenses

### Step 4 (optional): Budget limit

Add a variable like `budget_limit = 500` near `expenses = []` and show **remaining budget** on the summary page using the `total` you already calculate.

- [ ] (Optional) I experimented with a budget limit

---

## Part 3: Save to GitHub

**Source Control** -- message: `add budget buddy flask app with tailwind`

- [ ] I committed and synced

---

## Set Your Goal for Next Week

Open `TODO.md` and replace your rough line with **one specific** next step. Examples:

- "Show remaining budget against a set limit on the summary page."
- "Add a simple breakdown by category."
- "Save expenses to a file so they survive a server restart."

- [ ] I updated `TODO.md` with one specific goal for next week
- [ ] I saved, committed, and synced

---

## Troubleshooting

### "No module named flask"

`pip install flask` or `pip3 install flask`.

### Form submits but summary is empty

Check `expenses = []` is at the **top** of the file (not inside a function). Check `/add` includes `methods=["GET", "POST"]`.

### Page looks unstyled

Missing Tailwind `<script>` in `<head>`, or need to restart Flask and refresh.

### "Address already in use"

**Ctrl+C** in the terminal, then run again.

---

## Resources

- [Flask](../../resources/flask.resource.md)
- [Tailwind CSS](../../resources/tailwind.resource.md)
- [GitHub Codespaces Guide](../../resources/github-codespaces.guide.md)
- [Cursor Guide](../../resources/cursor.resource.md)
- [GitHub Basics](../../resources/github-basics.guide.md)
- [Prompting Cheat Sheet](../../resources/prompting-cheat-sheet.guide.md)
- [Project Folder Guide](../../resources/gh-project-folder.guide.md)

---

## Get Help From Your AI Agent

> I'm building a **budget tracker** Flask app for Demo Day. This week I'm working on: **[e.g. first run / form POST / summary total / Tailwind]**.
>
> Here's my code:
>
> ```
> [paste app.py or one function]
> ```
>
> Problem: **[describe. Paste terminal errors]**.
>
> Do not rewrite my whole project. Tell me what to check first, then small edits. Define new terms in one sentence.


---

## Backlinks

The following sources link to this document:

- [Week 4: Catch Up and Start Your Budget App](/users/john-p/index.path.llm.md)
- [Week 4 guide](/users/john-p/week-5.path.llm.md)
