← Vault Index
Source: tools/cadence/cadence-redesign-build-guide.md

Cadence Redesign Build Guide

From Broken to Working in One Session


Overview

This guide documents the process of redesigning and fixing the Cadence task management app. The session focused on simplifying the data model, fixing broken features, and streamlining the deployment workflow.

Time: ~5 hours (including recurring tasks) Result: Fully functional app with unified tasks, time blocking, goals, calendar views, and recurring tasks


What Made This Build Smoother

1. Git Credentials Embedded in Remote URL

The key improvement: storing the GitHub token directly in the remote URL.

git remote set-url origin https://YOUR-TOKEN@github.com/USERNAME/REPO.git

Why this matters:

To set this up:

  1. Create a Personal Access Token at https://github.com/settings/tokens/new
  2. Check repo scope
  3. Run the command above with your token
  4. All future pushes "just work"

2. Auto-Deploy Already Configured

Railway and Vercel were already connected to GitHub from the original build:

No manual deploys needed. Just push and wait 2-3 minutes.

3. Fix → Push → Test Live (Not Local)

Instead of wrestling with local database setup, we:

  1. Made code changes with Claude Code
  2. Pushed directly to GitHub
  3. Tested on the live site
  4. Read error messages from browser console + Railway logs
  5. Fixed and repeated

This avoided the entire "set up local PostgreSQL" rabbit hole.

4. Database Fixes Direct to Production

When the production database was missing columns, we fixed it directly:

# In Claude Code, with the DATABASE_URL:
psql "postgresql://postgres:xxx@xxx.proxy.rlwy.net:xxx/railway"

Then ran ALTER TABLE commands. No migrations, no downtime.


The Redesign Process

Phase 1: Planning (This Chat)

Before touching code, we designed:

Output: cadence-redesign-spec.md — a complete spec to hand to Claude Code

Phase 2: Database Migration

Claude Code created a migration script that:

  1. Renamed old tables (tasksold, sprinttasks_old)
  2. Created new unified tasks table
  3. Migrated data from both old tables
  4. Added new columns (color on sprints, outcome on cycles)
  5. Simplified goals (renamed columns)

Key insight: The migration ran locally but NOT on production. We had to manually add missing columns to the Railway database.

Phase 3: Backend Updates

Phase 4: Frontend Updates

Built/updated views in order:

  1. Tasks list view (grouped by Today/Tomorrow/This Week/Later)
  2. Tasks calendar view (side-by-side with day panel)
  3. Today view (time blocking grid)
  4. Sprint view (with colors, explicit completion)
  5. Cycle view (with goals and [+] increment)

Phase 5: Bug Fixes

Most bugs were database schema mismatches:

ErrorCauseFix
500 on create cycleMissing outcome columnALTER TABLE cycles ADD COLUMN outcome TEXT
500 on create goalColumns named wrongRenamed targetvalue → target, currentvalue → current
500 on create taskMissing columnsAdded starttime, estimatedminutes, sprint_id
Sprint dropdown emptyPromise.all failingSeparated fetches into independent try/catch

Debugging pattern:

  1. Try action in browser
  2. Check browser console for error code (500, 404, etc.)
  3. Check Railway logs for actual error message
  4. Fix database or code
  5. Push and retest

Key Commands Reference

Git (with embedded token)

# Set up once
git remote set-url origin https://TOKEN@github.com/USERNAME/REPO.git

# Then just push
git add .
git commit -m "Description"
git push origin master

Database Fixes (via Claude Code)

# Connect to Railway Postgres
psql "DATABASE_URL_HERE"

# Common fixes
ALTER TABLE tablename ADD COLUMN IF NOT EXISTS columnname TYPE;
ALTER TABLE tablename RENAME COLUMN old TO new;
\d tablename  -- show table structure
\q  -- quit

Debugging Stubborn Bugs

When a fix doesn't work, add logging at every step:

// Client - before API call
console.log('[Action] Sending:', { data, options });

// Client - after API response  
console.log('[Action] Server response:', response);

// Server - in route handler
console.log('[ROUTE] Params:', { id, mode, data });
console.log('[ROUTE] Branch:', 'which code path executed');

// Client - in data processing
console.log('[Process] Input:', rawData);
console.log('[Process] Output:', processedData);

Then trace the data flow to find where it breaks.

Check Deployment Status


What's Different from Original Cadence Build

Original BuildThis Redesign
Built features incrementallyStarted with complete spec
Local testing with SQLiteTest directly on production
Manual Vercel deploysAuto-deploy on push
Credential prompts every pushToken embedded in remote URL
Two task tablesOne unified table
Complex date fieldsSingle date field
Goals with "points"Goals as leading indicators

Final App Structure

Cadence
├── Dashboard (summary counts)
├── Today (time blocking)
│   ├── Time grid (15-min increments)
│   └── Unscheduled tasks panel
├── Tasks
│   ├── List view (grouped by date)
│   └── Calendar view (side-by-side with day panel)
├── Sprints
│   ├── Active / Upcoming / Completed sections
│   ├── Sprint detail with tasks
│   └── Explicit "Mark Complete" button
├── Cycles
│   ├── Current / Past sections
│   ├── Goals with progress bars and [+] increment
│   └── Linked sprints
└── Issues (existing feature)

Lessons Learned

  1. Spec first, code second — The planning conversation caught UX issues before writing code
  1. Production database ≠ local database — Migrations don't auto-run on Railway. Check Railway logs for "column does not exist" errors.
  1. 500 errors = check server logs — Browser console shows the error code, Railway logs show the actual message
  1. Embed git credentials — Saves 5 minutes of frustration on every push
  1. Test live, not local — Faster feedback loop when you skip local database setup
  1. Fix one bug at a time — Verify each fix before moving to the next
  1. Database columns must match code — When you get 500 errors on create/update, it's often a mismatch between what the code expects and what the database has. Fix with ALTER TABLE directly on Railway.
  1. Console.log is your friend — When a bug is stubborn, add logging at each step of the flow (client → server → back to client) to pinpoint exactly where it breaks.
  1. Timezone bugs are sneaky — new Date("2026-01-29") parses as UTC midnight, which shifts to the previous day in western timezones. Use local date parsing helpers when comparing dates.
  1. Clean URLs matter — /today is better than /cadence?tab=today. Use React Router for clean routes.
  1. Recurring tasks are deceptively complex — They need: instance generation, exclusions for completed/deleted, proper date passing for each instance, and special handling for the first occurrence (which comes from the original task, not generated instances).
  1. When porting features between apps, bring the bug fixes — We fixed recurring task bugs in Rapport, then applied the same patterns to Cadence. Document what you learn so you don't re-discover bugs.
  1. Test the specific instance, not just the feature — "Delete works" isn't enough. Test: delete today's instance, delete a future instance, delete all. Each path can break differently.
  1. Use the app for real — Building is one thing. Using it daily will reveal what's actually missing or broken.

Next Steps (Future Sessions)


Guide created: January 29, 2026