You've shipped Phase 1. Here's what Phase 2 could look like — pick one thing and build it.
Day 39 of 80
Take a moment to recognize what you've built in 8 weeks:
This is a real tool. Today is about extending it — but only the feature that would genuinely make it more useful for you.
Do not try to build all six features below. Pick the single feature you would actually use. Build just that. Finish it. One complete feature is worth more than five half-built ones.
Add a tags array to each prompt, then filter the library by tag. This makes the vault useful as it grows beyond 30-40 prompts.
{
"platform": "Kling",
"shot": "aerial establishing shot",
"prompt": "Wide drone shot ascending over misty mountains...",
"tags": ["aerial", "establishing", "nature"],
"created_at": "2025-01-15T10:30:00"
}
Add a tags input to the generation form. Split by commas: tags = request.form.get("tags", "").split(","). In the template, show clickable tag badges that trigger a filter by tag.
Add a favorited boolean field to each prompt. A star button toggles it. A "Favorites Only" filter shows just favorited prompts.
@app.route("/favorite/<int:index>", methods=["POST"])
def toggle_favorite(index):
prompts = load_prompts()
if 0 <= index < len(prompts):
current = prompts[index].get("favorited", False)
prompts[index]["favorited"] = not current
save_prompts(prompts)
return redirect(url_for("index"))
In the template, add a small form button for each prompt: a star (★/☆) that POSTs to this route. The favorited value determines which star you show.
A route that returns all prompts as a downloadable .txt file — useful for copying into video production docs or sharing with collaborators.
from flask import Response
@app.route("/export")
def export_prompts():
prompts = load_prompts()
lines = []
for i, p in enumerate(prompts, 1):
lines.append(f"--- Prompt {i} ---")
lines.append(f"Platform: {p['platform']}")
lines.append(f"Shot: {p['shot']}")
lines.append(f"Prompt: {p['prompt']}")
lines.append("")
content = "\n".join(lines)
return Response(
content,
mimetype="text/plain",
headers={"Content-Disposition": "attachment; filename=prompt-vault-export.txt"}
)
The Content-Disposition: attachment header tells the browser to download the file rather than display it. Add an "Export All" button to your template pointing to /export.
Add an edit route that loads a single prompt into a pre-filled form, then saves the changes back to the same index position.
@app.route("/edit/<int:index>", methods=["GET", "POST"])
def edit_prompt(index):
prompts = load_prompts()
prompt = prompts[index]
if request.method == "POST":
prompts[index]["prompt"] = request.form.get("prompt_text")
prompts[index]["shot"] = request.form.get("shot")
save_prompts(prompts)
return redirect(url_for("index"))
return render_template("edit.html", prompt=prompt, index=index)
You'll need a new template edit.html with a form pre-populated with {{ prompt.shot }} and {{ prompt.prompt }}. The GET loads the form; the POST saves it.
A simple stats page showing a breakdown of prompts by platform. You can render this with a basic HTML bar chart or use Chart.js for something visual.
@app.route("/stats")
def stats():
prompts = load_prompts()
counts = {}
for p in prompts:
platform = p.get("platform", "Unknown")
counts[platform] = counts.get(platform, 0) + 1
total = len(prompts)
return render_template("stats.html", counts=counts, total=total)
In the template, loop over counts.items() to show platform names and counts. For Chart.js, pass the data as JSON and let JavaScript render the chart. This is a great introduction to passing data from Python to a frontend library.
Adding real user accounts requires Flask-Login — a library you'll cover in Week 12. For now, you could add basic HTTP Basic Auth as a simple password gate, or just note this as a future milestone.
from functools import wraps
from flask import request, Response
def require_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.authorization
if not auth or auth.password != os.environ.get("APP_PASSWORD"):
return Response("Unauthorized", 401,
{"WWW-Authenticate": 'Basic realm="Prompt Vault"'})
return f(*args, **kwargs)
return decorated
# Then decorate your index route:
@app.route("/")
@require_auth
def index(): ...
This is a decorator pattern — Python wrapping a function with extra behavior. You'll study decorators formally in Week 10. This is a sneak peek at how Flask uses them.
Day 40 is a reflection day — no new code. You'll look back at where you started and forward at what Part 2 brings. It's also a good day to write down what you'd do differently if you rebuilt the Prompt Vault from scratch with everything you now know.