Day 15: Feature-First Workflow Building a Complete Feature in One Session

Learn the feature-first workflow for Claude Code. Five-component brief, seven-step process, complete billing page example. One session, one feature, done.

Day 15: Feature-First Workflow Building a Complete Feature in One Session

Hey, it's G.

Day 15 of the Claude Code series.

Day 14 was the vibe coding mindset.

Today is the actual workflow.

How to take a feature from idea to working code in one session.

Let me show you the structure that makes it work.


The Problem (Winging It Gets You Messy Half-Finished Features)

Here's how I used to build features before I had a workflow:

claude

> Build a user profile page

[Claude starts building...]

> Wait, it should also let them edit their email

[Claude adds email editing...]

> Actually, use the existing form pattern from LoginForm

[Claude refactors to match pattern...]

> Oh and don't install new dependencies

[Claude removes dependencies, refactors again...]

> And it needs to save to Supabase

[Claude adds Supabase integration...]

> Wait no, Supabase is already configured in /lib/supabase.ts

[Claude refactors again...]

By the end:

  • Ten rounds of back-and-forth
  • Inconsistent code from constant redirects
  • Half the session spent clarifying what I actually wanted
  • Messy commits from incremental fixes

The problem: I was figuring out what I wanted while Claude was building it.


The Concept (Feature-First Workflow)

A feature-first workflow means you treat each Claude Code session as a complete unit of work.

One session. One feature. Done.


Most developers use Claude Code reactively:

Hit a problem → Ask for help → Apply the fix → Move on

Feature-first is the opposite:

Define the full scope upfront → Let Claude Code plan the implementation → Execute from top to bottom without losing the thread


The key insight:

Claude Code works best when it has full context of what you're building before it touches a single file.

A complete feature brief at the start of a session is worth more than ten back-and-forth clarifications mid-way through.


The Five Components of a Solid Feature Brief

Before opening Claude Code, write down these five things:

1. What It Does

The feature in plain English. What does the user see? What can they do?

2. Where It Lives

Which routes, files, or folders are involved. New files? Existing files?

3. What Already Exists

Patterns, components, or configs to reuse. Don't reinvent what you already have.

4. What Done Looks Like

Acceptance criteria. List them. This is your definition of complete.

5. What to Avoid

Constraints and things not to touch. Files, dependencies, patterns to avoid.


Get those five things into your opening prompt and the entire session runs cleaner.


The Feature Brief Template

Here's the template I use every time:

We are building a [feature name] today.

What it does: 
[plain English description of what the user sees and does]

Where it lives: 
[routes, files, folders — be specific]

What exists already: 
[components, configs, patterns to reuse]

What done looks like: 
[acceptance criteria — list them clearly]

What to avoid: 
[constraints, files not to touch, dependencies not to add]

Do not write any code yet.

That last line is important:

"Do not write any code yet."

Forces Claude Code to wait for the /plan step instead of jumping straight to implementation.


The Seven-Step Feature-First Workflow

Step 1: Write Your Feature Brief (Before Opening Claude Code)

Take 2 minutes before starting a session.

Don't wing the brief. Write it out.

The clearer your opening prompt, the less redirecting you do later.


Step 2: Orient Claude Code with the Full Brief

cd ~/projects/my-app
claude

Paste your complete feature brief:

We are building a user profile page today.

What it does: 
Logged-in users can view and edit their display name, 
email, and avatar. Changes save to Supabase.

Where it lives: 
/app/profile/page.tsx (new route)
/components/profile/ProfileForm.tsx (new component)

What exists already: 
- Supabase auth configured in /lib/supabase.ts
- Existing form pattern in /components/auth/LoginForm.tsx
- Button and Input components in /components/ui/

What done looks like: 
- User can view their current profile data
- User can edit display name and email
- Changes persist to Supabase on save
- Success and error states handled
- Matches visual style of existing pages

What to avoid: 
- Don't touch /lib/supabase.ts
- Don't install new dependencies
- Don't modify existing auth flow

Do not write any code yet.

Step 3: Plan

> /plan

Claude responds with detailed plan:

Plan for user profile page:

Files to create:
1. /app/profile/page.tsx
   - Main profile page route
   - Fetches current user data on load
   - Renders ProfileForm component

2. /components/profile/ProfileForm.tsx
   - Controlled form with display name and email inputs
   - Uses existing Button and Input from /components/ui/
   - Follows pattern from LoginForm.tsx
   - Handles submit, success, and error states

Files to read (for patterns/config):
- /lib/supabase.ts (Supabase client)
- /components/auth/LoginForm.tsx (form pattern)
- /components/ui/Button.tsx
- /components/ui/Input.tsx

Implementation steps:
1. Create /app/profile/page.tsx
2. Fetch current user with Supabase auth
3. Create ProfileForm component
4. Implement controlled inputs
5. Handle form submission
6. Update user data in Supabase
7. Show success/error feedback

No new dependencies needed.
Using existing Supabase client from /lib/supabase.ts

Proceed?

Review the plan carefully.

This is your last easy checkpoint before code gets written.

Ask yourself:

  • Does it plan to touch files it shouldn't?
  • Is the approach consistent with existing patterns?
  • Is anything missing from the scope?

If something's wrong, redirect here:

> Good plan but don't create separate ProfileForm component yet. 
> Build everything in page.tsx first. We can extract later if needed.

If it's good, approve:

> Looks good. Go ahead and build it.

Redirecting at the plan stage is much cheaper than redirecting after the code is written.


Step 4: Execute

Claude Code builds the entire feature.

Your job:

Stay in the director's chair. Let Claude Code work through the plan.

Don't interrupt for small things — let it complete logical chunks.


Step 5: Review Each Chunk

After each major chunk completes (new component built, API route created, etc.), run a review:

> /review

Claude responds:

Review findings:

/app/profile/page.tsx:
✅ Fetches user data correctly
✅ Handles loading state
✅ Handles error state
⚠️ Line 45: Success message disappears immediately
   Fix: Add 3-second delay before clearing message

/components/profile/ProfileForm.tsx:
✅ Follows LoginForm.tsx pattern
✅ Uses existing Button and Input components
✅ No new dependencies added
✅ Controlled inputs working correctly

Summary: 1 issue found. Fix suggested above.

Catch issues early before they compound into the next chunk.

One issue after one component = easy fix.

One issue after ten components = painful refactor.


Step 6: Redirect with Outcome Language

When redirecting, describe the outcome you want, not implementation details:

❌ Not this (implementation):

> Change line 45 to use setTimeout with 3000ms delay 
> before setting successMessage to null

✅ This (outcome):

> The success message disappears too fast. 
> Keep it visible for 3 seconds then fade out.

Claude makes the fix. Review again:

> /review

All clear.


Step 7: Ship

> /ship

Claude responds:

Pre-Commit Workflow Complete

1. REVIEW FINDINGS:
✅ No issues found

2. CONVENTION CHECK:
✅ Named exports only
✅ No `any` types
✅ Tailwind utilities only
✅ All files under 150 lines

3. SUGGESTED COMMIT MESSAGE:
add user profile page with edit functionality

Implemented profile page where users can view and edit
display name and email. Changes persist to Supabase.
Follows existing form pattern from LoginForm.

Files created:
- /app/profile/page.tsx
- /components/profile/ProfileForm.tsx

4. FOLLOW-UP TASKS:
- Add avatar upload in next session
- Add email verification flow
- Write tests for profile update logic

Complete feature. Clean session. One commit.


Real Feature Build (Start to Finish)

Let me walk you through a complete real session building a billing page for Resiboko.


Step 1: Feature Brief (Written Before Opening Claude Code)

We are building a billing page today.

What it does:
Users can view their current subscription plan (Free or Pro),
see how many expenses they've logged this month vs their limit,
and upgrade to Pro with a Stripe checkout button.

Where it lives:
/app/billing/page.tsx (new route)
/utils/stripe/createCheckout.ts (new utility)

What exists already:
- Stripe configured in /lib/stripe.ts
- Layout pattern in /app/dashboard/page.tsx
- Card components in /components/ui/
- Supabase auth for user ID

What done looks like:
- Current plan displayed (Free or Pro)
- Usage count displayed (X/100 for Free, unlimited for Pro)
- Upgrade button (disabled if already Pro)
- Clicking upgrade opens Stripe checkout
- Success/error states handled
- Dark mode support via Tailwind

What to avoid:
- Don't touch /lib/stripe.ts
- Don't install new dependencies
- Don't modify existing auth flow
- Don't create new database tables

Do not write any code yet.

Step 2: Orient

cd ~/projects/resiboko
claude

Paste the complete brief:

We are building a billing page today.

[... full brief from above ...]

Do not write any code yet.

Step 3: Plan

> /plan

Claude responds:

Plan for billing page:

Files to create:
1. /app/billing/page.tsx
   - Main billing page
   - Fetch subscription status from Stripe
   - Display plan tier (Free/Pro)
   - Display usage count vs limit
   - Upgrade button with Stripe checkout

2. /utils/stripe/createCheckout.ts
   - Helper to create Stripe checkout session
   - Returns checkout URL
   - Uses existing Stripe client

Files to read:
- /lib/stripe.ts (Stripe client config)
- /app/dashboard/page.tsx (layout pattern)
- /components/ui/Card.tsx

Implementation approach:
- Match dashboard card layout
- Use Supabase auth for user ID
- Fetch subscription from Stripe
- Free tier: 100 expense limit
- Pro tier: unlimited
- Upgrade button creates checkout session
- Redirect to Stripe hosted checkout

No new dependencies needed.
No database changes required.

Estimated steps: 10

Proceed?

I review the plan.

Looks good. I approve:

> Looks good. Go ahead and build it.

Step 4: Execute

Claude Code builds:

  1. Creates /app/billing/page.tsx
  2. Creates /utils/stripe/createCheckout.ts
  3. Implements fetch logic
  4. Implements UI
  5. Implements upgrade button

I don't interrupt. Let it complete the full implementation.


Step 5: Review

> /review

Claude responds:

Review findings:

/app/billing/page.tsx:
✅ Matches dashboard layout pattern
✅ Dark mode implemented correctly
✅ Loading and error states present
✅ Upgrade button disabled when plan is Pro
⚠️ Line 78: Usage percentage not displayed
   Fix: Add percentage calculation and display label

/utils/stripe/createCheckout.ts:
✅ Uses existing Stripe client correctly
✅ No new dependencies added
✅ Error handling present

Summary: 1 issue found. Fix suggested above.

Step 6: Redirect

> Good catch. Add the percentage label showing how close 
> Free tier users are to their 100 expense limit.

Claude makes the fix.

Review again:

> /review

All clear.


Step 7: Ship

> /ship

Claude responds:

Pre-Commit Workflow Complete

1. REVIEW FINDINGS:
✅ No issues found

2. CONVENTION CHECK:
✅ Named exports only
✅ No `any` types
✅ Tailwind utilities only
✅ Dark mode working
✅ All files under 150 lines

3. SUGGESTED COMMIT MESSAGE:
add billing page with subscription management

Implemented billing page showing current plan (Free/Pro),
monthly usage count with limit tracking, and Stripe checkout
integration for Pro upgrades. Matches dashboard layout.

Files created:
- /app/billing/page.tsx
- /utils/stripe/createCheckout.ts

4. FOLLOW-UP TASKS:
- Add Stripe webhook handler for subscription updates
- Add success/cancel return URLs for checkout
- Write tests for checkout creation
- Add analytics tracking for upgrade attempts

Perfect. I copy the commit message and commit.


Complete feature:

  • One session
  • ~30 minutes
  • I wrote 7 prompts total (brief, /plan, approve, /review, redirect, /review, /ship)
  • Clean commit
  • Production-ready code

That's the workflow.


Why This Matters

The feature-first workflow turns Claude Code from a helpful assistant into a reliable execution engine.

When you bring a complete brief, Claude Code can build the whole thing coherently:

  • Consistent patterns throughout
  • No half-finished pieces
  • No context lost mid-session
  • Clean commits

The developers shipping fastest right now aren't using Claude Code more.

They're using it more intentionally.

Brief → Plan → Execute → Review → Redirect → Ship

That's the system.


Common Mistakes (What NOT to Do)

❌ Mistake 1: No Brief, Just Start Coding

> Build a profile page

[Claude starts...]

> Wait it should also...

Result: Constant redirects, messy session.


❌ Mistake 2: Skipping the Plan Step

> Build a billing page with everything

[Claude jumps straight to code...]

Result: No chance to review approach before code is written.


❌ Mistake 3: Interrupting Too Much

> Build the form

[Claude writes first input...]

> Make that input bigger

[Claude adjusts...]

> Actually move it to the right

[Claude moves it...]

Result: Flow killed, no progress on actual feature.


❌ Mistake 4: No Review Between Chunks

> Build components A, B, C, D, E

[Claude builds all five...]

> /review

[Five issues found, all compound on each other...]

Result: Painful refactor across multiple files.


❌ Mistake 5: No Ship Command

[Session ends]
[Files modified but no review, no commit message, no notes]

Result: Messy git history, no record of what was done.


My Raw Notes (Unfiltered)

This is the workflow I wish I had when building Resiboko.

I was just firing off prompts as I thought of them and ending up with messy half-finished features.

The brief template is the real unlock — 2 minutes of thinking before the session saves 20 minutes of redirecting during it.

The review after each chunk habit is underrated. Catching a wrong pattern after one component is easy. Catching it after ten components is painful.

The /ship at the end turned into a non-negotiable for me — it forces a clean close to every session.

The brief doesn't need to be perfect. Just complete. All five components covered.


Tomorrow (Day 16 Preview)

Topic: Debugging with Claude Code — how to let it find and fix its own mistakes without you becoming the middleman.

What I'm testing: Can Claude Code debug its own code? How do you guide it to find bugs without telling it exactly where they are?


Following This Series

Phase 3 (Days 15-21): Vibe Coding ⬅️ You are here

So far in Phase 3:

  • Day 14: Vibe coding mindset
  • Day 15: Feature-first workflow (today)
  • Day 16: Debugging with Claude Code (tomorrow)

G

P.S. - The five-component brief: what it does, where it lives, what exists, what done looks like, what to avoid. Takes 2 minutes. Saves 20 minutes of redirecting.

P.P.S. - Review after each major chunk, not after the entire feature. Catch issues early before they compound.

P.P.P.S. - Always end with /ship. Pre-commit review, convention check, commit message, follow-ups. Clean close every session.