2026-07-21

Grooming Before Coding: Scoping the Beer App's Auth II Sprint

Sprint 3 of the beer app closed this week: search-first browsing, real external data integrations, a mobile UX pass. The next named sprint on the roadmap is Auth II — social sign-in and password reset — and today's session didn't touch a single line of application code. It scoped the sprint instead: one GitHub milestone, seven issues, each sized to ship and test independently. That's worth a post on its own, because the scoping decisions are where most of the actual thinking happens.

The research came first, and it wasn't wasted

The project already had a decision on file from an earlier planning pass: use ASP.NET Core Identity's built-in external login providers for Google, Facebook, and Apple, rather than bolting on a hosted identity vendor. Before turning that decision into issues, I re-read it against the current code — the AuthController that issues JWTs today, the Program.cs Identity configuration, what packages are and aren't installed yet.

That check surfaced something the original plan hadn't spelled out: the app has no custom user class. Every place in the code refers to Identity's bare, built-in user type. Adding a marketing-consent checkbox — a real requirement here, not a nice-to-have, since it needs to be captured and stored per account — means introducing a custom user class and a database migration before any consent checkbox can exist. That became its own foundational issue, first in the sprint, because everything downstream depends on it.

One dependency, two consumers

Password reset needs to send an email. That's a small requirement on paper, but it's also the first time this project has needed to send an email at all, for anything. Rather than treat it as an implementation detail buried inside the password-reset story, it became its own issue: a pluggable email-sender abstraction, config-driven the same way an earlier story handled a third-party API key — safe to leave unconfigured, silent rather than broken when it is.

The reason to isolate it: the project's own roadmap already has a second consumer waiting. Push notifications, planned for a much later sprint, will need to send messages too. Building the sender as its own piece now, instead of inline inside password reset, means that later sprint inherits working infrastructure instead of a second implementation of the same problem.

Bundling for the right reason

Facebook's platform requires a privacy policy and an account-deletion path before it will approve login integration. Those two things aren't really about Facebook — a privacy policy and a way to delete your data are good practice regardless of which button a customer clicks to sign in. But Facebook is the forcing function that puts them on the sprint board now instead of later, so they got bundled into the Facebook sign-in story rather than split into their own tickets nobody would prioritize. Sometimes the right shape for a story isn't "one clean concern," it's "the thing that's actually going to get built together."

The PM angle

None of this took long — one research pass, one round of scoping, seven issues written with enough detail that whoever picks each one up next (including future me) doesn't have to re-derive the decisions above. But skipping it is the easy failure mode on a solo project: no one is in the standup asking "wait, what's actually in this sprint?", so it's tempting to just start writing the Google sign-in code and figure the rest out as you go. The cost of that shows up later, as rework, when the marketing-consent field needed for issue five turns out to require a migration that should have been issue one.

Grooming is cheap. Re-scoping mid-sprint because the first story didn't account for the third one isn't.

Where the project stands

Three sprints shipped, the fourth fully scoped and sitting in the backlog as seven ready-to-pick-up issues: a data migration, a shared email dependency, three independent OAuth integrations, a password-reset flow, and the UI that ties it together. Nothing to demo yet — that comes next.

Comments

Loading comments...