Nobody has started this yet — be first.
Business impact
flask seed-db exists specifically so a new developer (or this project's own README) can boot the app and immediately see the custom-slug feature working, per the README's quick-start walkthrough. Right now the seeded "custom slug" example does not actually end up with its custom slug -- it silently gets an auto-generated one instead. Anyone following the quick-start to explore the custom-slug feature will look for /python-docs and get a 404, land on the wrong first impression of a brand new project, and have to go spelunking in app/cli.py to figure out why the demo data does not match the README.
Problem
The custom ShortURL is constructed with slug="python-docs", but the code then does db.session.flush() followed by custom.slug = base62.encode(custom.id), clobbering the slug it was just given.
Current behavior
The flush() + custom.slug = base62.encode(custom.id) pair is the exact pattern used for the auto-generated slug example two lines above it -- copy-pasted down into the custom-slug block without noticing that block already had the slug it wanted. After flask seed-db, the row with target_url == "https://docs.python.org/3/" ends up with a base62-encoded numeric slug, not "python-docs".
Expected behavior
After flask seed-db, there is a ShortURL row with target_url == "https://docs.python.org/3/" and slug == "python-docs".
Steps to reproduce
Why this matters
This is the two-phase-insert pattern (flush() to get an id, then set the final slug) applied to the wrong branch. The custom-slug branch already has its final slug at construction time and never needed a flush-then-overwrite at all -- that dance is only necessary when the slug itself depends on the row's own id, which is not true here.
Suggested approach
Look at why the auto-generated examples (example, soon_expiring) need the flush() + base62.encode(...) dance, and confirm the custom block does not share that reason. Remove whatever doesn't belong in the custom block rather than changing the auto-generated blocks.
Acceptance criteria
Verification
pytest practice_tickets/tests/test_ticket_06_seed_db_custom_slug.py -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b fix/seed-db-custom-slug-clobberedFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/seed-db-custom-slug-clobberedSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign indocker-entrypoint.shcurl -X POST http://localhost:5000/api/urls \
-H "Content-Type: application/json" \
-d '{"target_url": "https://anthropic.com", "custom_slug": "claude"}'
# -> {"slug": "claude", "short_url": "http://localhost:5000/claude", "expires_at": null}
curl -i http://localhost:5000/claude # 302 redirect, records a click
make seed # or: docker compose exec web flask seed-db
If something is already listening on 5432/6379 locally, uncomment POSTGRES_HOST_PORT / REDIS_HOST_PORT in .env to remap the host side — the app always talks to db/redis over the compose network regardless. Run production-style (gunicorn, no dev server, no bind mount) with docker compose -f docker-compose.prod.yml up --build. GET /healthz checks both Postgres and Redis connectivity.
You do not need Docker running at all to work the tickets — the test suite uses TestingConfig (SQLite in-memory via StaticPool) and fakeredis instead of a real Postgres/Redis, so everything runs against a plain virtualenv:
python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/pytest practice_tickets/tests/test_ticket_01_base62_roundtrip.py -v # a single ticket
./practice_tickets/run_tickets.sh # all 20, clean pass/fail summary
./practice_tickets/run_tickets.sh 05 13 16 # just a few, by number
All 20 tests fail at the start; as you fix each ticket in app/, its test (and only its test) should flip to passing. .venv/bin/pytest tests/ (via make test) runs the project's own main suite — some ticket bugs (TICKET-05, 07, 08, 09, 14 among others) also break assertions in that suite, since they are real bugs in shared code paths; fixing the ticket fixes those too, not a separate task.
Level 1
Fix a bug
Read existing behaviour, correct it.