Couch Tour Invitational
Clubhouse
Michigan · September 2026
--
days until tee off
Sept 29 โ€“ Oct 4, 2026 ยท Michigan
Select a round above to begin scoring
No scores entered yet

CTI 2026

Couch Tour Clubhouse

?
Select Player
Tap to change
Players
Roster, contact & teams
Courses
Course handicaps per player
Flights
Arrival & departure info
Rules
Local rules & game formats
Hall of Quotes
Things said on the course
Archives
Trip history & all-time records
App Info
Install guide & about

CTI 2026

Players

CTI 2026

Rules

Local Rules
Lift, clean & place throughout
Everything is a lateral hazard
Divots are ground under repair
Breakfast ball on every 1st tee โ€” use it or lose it
Everything is waste area, including bunkers (ground your club)
Match Play Format
2 teams of 4 โ€” partners rotate each round
Better ball match play: best net score per pair per hole
Each hole worth 1 point โ€” tied holes = 0 pts to both
90% handicap applied to hardest holes by stroke index
Most total points after 5 rounds wins the CTI
๐Ÿ”ฅ On Fire Rule
3 consecutive pars or better = you're on fire
Every subsequent par or better stays on fire
A bogey or worse ends the streak
Fire scores are permanently marked on the scorecard
While on fire, all putts within the length of your putter are given
๐Ÿ‘‘ Prince of Wales
Team game across all 5 rounds
Best raw score from any teammate on each hole number
Build the ultimate 18-hole composite scorecard
Lowest total after all rounds wins
Winning team earns 5 bonus points added to the final tournament total
๐Ÿ’ฐ Tournament Purse
The losing team at the end of the tournament pays the welcome dinner bill
Bill is split evenly 4 ways among the losing team's players
If tied, both teams split it 8 ways

CTI History

Hall of Quotes

Add Quote
Type
Who said it
The Quote
Context (optional)
Year
Trip

Michigan 2026

Courses

CTI 2026

Flights

CTI 2026

App Info

Add to Home Screen

Install the Clubhouse app on your home screen for quick access.

iPhone Instructions
Safari ยท 4 steps
Android Instructions
Chrome ยท 3 steps
Troubleshooting

If you're having any issues with the app, clearing your browser cache will often resolve the problem.

Clear Safari Cache
iPhone ยท 4 steps
Clear Chrome Cache
Android ยท 3 steps
About
App CTI Clubhouse
Version v2026.06.09
Website cticlubhouse.com
Built by Owen Chamberlin
Copyright © 2026 Owen Chamberlin

CTI 2026

Commissioner Docs

Commissioner Only ยท CTI 2026

App Documentation

Behavioral reference for CTI Clubhouse ยท v2026.06.09

01

Home Page

Countdown Widget

WhenWhat it shows
Before tripLarge number (days remaining) + "days until tee off" + "Sept 29 โ€“ Oct 4, 2026 ยท Michigan"
Sep 29"Welcome to the Couch Tour Invitational! Safe Travels"
Sep 30"Day 1: Practice Round"
Oct 1"Day 2: Tournament Begins!"
Oct 2"Day 3: On To Arcadia Bluffs"
Oct 3"Day 4: The Final Day"
Oct 4 +"Thanks for Playing. See You Next Year!" (persists forever after trip)

Dates are hardcoded. The getTodayKey() function returns the current date key โ€” outside trip dates it returns '9-30' as a fallback for tee times display.

Tee Times Widget

Shows today's rounds from TODAY_SCHEDULE keyed by date. Displays course name, Practice/Tournament badge, and both tee times (Pairing 1 / Pairing 2). Hidden when no schedule exists for today. On post-trip dates the entire widget is replaced by the Trip Summary.

Weather Widget

Fetches live data from Open-Meteo API using hardcoded coordinates for each trip day's course location. Shows current temp (ยฐF), weather description, wind speed, humidity, and daily high/low. Falls back to "Live on trip" placeholder if fetch fails or app is in preview mode. Hidden entirely after Oct 4.

Daily MVPs Widget

Only visible during the trip (hidden after Oct 4). Shows three categories:

  • Most Points โ€” player with most individual match play points today
  • Best Net โ€” player with best net score relative to par today
  • Most Drinks โ€” player with most drinks tracked today

Shows placeholder "MVPs will appear after the first round is complete" until at least one of today's rounds is fully scored. If two rounds happen on the same day (Oct 3), it accumulates across both.

SH*T TALK THREAD (Chat)

Real-time group chat backed by Supabase messages table. Any player can send messages. Messages persist for the life of the app. The input is disabled until a player is selected. Duplicate messages are prevented via optimistic rendering โ€” an optimistic message is pushed immediately on send, then replaced by the real Supabase record when the INSERT event arrives via WebSocket.

Post-Trip State (after Oct 4)

The tee times, weather, and MVP widgets are all hidden. The countdown area is replaced by a Trip Summary showing final team points per round and the tournament winner.

02

Score Tab

Round Pills

5 pills: FD ยท Loop ยท South ยท Dozen ยท Bluffs. Active pill highlighted navy. Tap to switch rounds. Selection persists in localStorage.

Pairing Toggle

Two buttons: Pairing 1 / Pairing 2. Each pairing is 2v2 better ball match play. Pairings per round:

  • R1 Forest Dunes: P1: Ben+Bryan vs Jon+Nate ยท P2: Cody+Jeff vs Owen+Steve
  • R2 Loop Black: P1: Ben+Cody vs Jon+Owen ยท P2: Bryan+Jeff vs Nate+Steve
  • R3 South: P1: Ben+Jeff vs Jon+Steve ยท P2: Bryan+Cody vs Nate+Owen
  • R4 Dozen: P1: Ben+Bryan vs Jon+Owen ยท P2: Cody+Jeff vs Nate+Steve
  • R5 Bluffs: P1: Ben+Cody vs Jon+Nate ยท P2: Bryan+Jeff vs Owen+Steve

Scorecard Layout

7-column grid: Hole ยท Par ยท TBD ยท TBD ยท PTS ยท TBD ยท TBD. Column headers will show player names once teams are assigned. Navy = Team 1, Green = Team 2.

For 12-hole rounds (The Dozen), the scorecard splits into "Front Six" and "Back Six" instead of front/back nine. Subtotals show at the halfway point and at the end.

Score Entry

Tap any score cell โ†’ modal opens with โˆ’ / + controls for score and drink count. Tap outside or save to confirm. Scores save to Supabase immediately and broadcast to all connected devices via WebSocket.

Score color coding:

  • Eagle or better โ€” navy circle with navy ring outline
  • Birdie โ€” light blue circle
  • Par โ€” light grey (default)
  • Bogey โ€” light salmon/pink
  • Double bogey โ€” red circle with red ring outline
  • Triple+ โ€” red diagonal stripe pattern

Fire / Heating Up

Calculated on net scores (gross minus handicap strokes on that hole).

  • 3+ consecutive net pars or better = player is on fire ๐Ÿ”ฅ
  • Fire score cells get an orange border + flame emoji overlay
  • Streak resets the moment a net bogey or worse is posted
  • Works across the full round including the break between front and back nine
  • The Dozen: streak can carry across the midpoint (hole 6 โ†’ hole 7)

Stroke Dots

Stroke dots appear below the score button on holes where a player receives a handicap stroke.

  • 1 stroke โ€” single filled navy dot, bottom-left corner of score button
  • 2 strokes โ€” same dot with a tight ring around it
  • Shared stroke hole (all 4 players in the pairing stroke) โ€” dot fades to 20% opacity

Current state: SUPPRESS_SHARED_STROKE_DOTS = true โ€” all dots suppressed until course handicaps are entered. When you populate course handicaps, flip this flag to false.

Important: Course handicaps in the COURSES array must already be pre-calculated at 90% of USGA course handicap. Do NOT enter raw handicap index โ€” enter the final adjusted value. The 90% fallback formula has been removed.

Match Play Points (PTS column)

Each hole: better ball net score from each side is compared.

  • Team 1 wins hole โ†’ โ€น chevron in PTS column, Team 1 gets 1 point
  • Team 2 wins hole โ†’ โ€บ chevron in PTS column, Team 2 gets 1 point
  • Halved hole โ†’ โ—† diamond, no points
  • Incomplete hole โ†’ dot placeholder

Subtotal rows show running team point totals at Out and final Total.

Drink Counter

Long-press (or hold) a score button to add a drink for that player on that hole. Drinks also have a manual tracker in the Stats tab for drinks consumed outside of scoring.

03

Leaderboard Tab

Two Views: Tournament & Prince of Wales

Toggle between the two tabs at the top of the leaderboard page.

Tournament View

Shows cumulative team points across all 5 tournament rounds and both pairings. Each team card shows total points and a per-round breakdown row.

Point accumulation rules:

  • Points accumulate across all rounds and both pairings โ€” there is no per-round reset
  • Individual player points: player earns a point only if (a) their team won the hole AND (b) their net score tied for the lowest net on their side of the pairing
  • Practice rounds (Loop Red, Bootlegger) do NOT count toward tournament points

Prince of Wales View

Head-to-head individual match play standings. Each player is matched against their opposite-number pairing partner across rounds. Shows individual W/L/T record.

04

Stats Tab

What Each Stat Tracks

  • Total Points โ€” individual match play points across all tournament rounds
  • Net Birdies โ€” holes where net score was 1 under par
  • Net Eagles โ€” holes where net score was 2+ under par
  • Net Bogeys โ€” holes where net score was 1 over par
  • Best Round โ€” lowest gross 18-hole total (12-hole rounds excluded)
  • Worst Round โ€” highest gross 18-hole total (12-hole rounds excluded)
  • Fire Streak โ€” longest consecutive net par-or-better streak in a single round
  • Drinks โ€” total drinks (hole-by-hole + manual)

Note: Best/Worst Round explicitly excludes The Dozen (12 holes) to avoid skewing gross totals.

05

Tee Times Tab

Schedule

Shows the full week schedule from the SCHEDULE array. Each day lists course name, tee times (both groups), and a Practice/Tournament badge. This is a static display โ€” it does not change based on date.

Current tee times:

  • Wed 9/30: Loop Red 10:26/10:37am (Practice) ยท Bootlegger 4:30/4:41pm (Practice)
  • Thu 10/1: Forest Dunes 9:24/9:53am ยท Loop Black 2:50/3:01pm
  • Fri 10/2: South Course 1:39/1:50pm
  • Sat 10/3: The Dozen 9:06/9:18am ยท The Bluffs 1:40/1:50pm
06

Live Match Banner

What It Shows

A floating banner above the nav bar showing the current round name + "Live Match", with one row per pairing showing match status (e.g. "Warthogs lead 3โ€“1 ยท Thru 7") and holes played.

The banner floats across all tabs โ€” it persists when you navigate between Home, Score, Leaderboard, etc.

Visibility Rules

ConditionBanner State
10 min before tee time (on correct date, no scores yet)Shows "All Square" for both pairings โ€” pre-round mode
Scores being entered, round incompleteShows live match scores, updates in real time
Round complete, same day, before 9pmShows final result โ€” persists until 9pm
9pmโ€“4amHidden
4am, same day as roundResumes showing (Priority 2/4)
Day after round's scheduled dateNever shows for that round again
Next day, 10 min before next roundPre-round "All Square" appears for new round

Priority System (internal)

  • Priority 1 โ€” today's round, in progress โ†’ live scores
  • Priority 2 โ€” today's round, complete โ†’ final result until 9pm
  • Priority 3 โ€” outside trip dates, in progress round โ†’ live scores (testing)
  • Priority 4 โ€” outside trip dates, completed round on its scheduled date โ†’ final result until 9pm
  • Pre-round โ€” checked first before all priorities; fires only on exact calendar date, 10 min before tee time, zero scores

Once a round's scheduled date has passed, it is permanently excluded from all banner priorities.

Match Status Text

  • "Warthogs lead 3โ€“1" / "Grandmas lead 2โ€“1" โ€” in progress
  • "Warthogs win 5โ€“1" / "Grandmas win 4โ€“2" โ€” round complete
  • "All Square" โ€” tied or pre-round
  • "Tied 3โ€“3" โ€” complete, exact tie

Team names are pulled from TEAM_NAMES. Plural team names use "lead"/"win" (grammatically correct for group nouns).

07

Menu / Drawer Pages

Players

Shows all 8 players with email, phone, handicap index, and tee group. Handicap shows "TBD" in navy until populated. Team badge shows "TBD" until teams are assigned. Tap email/phone to open mail/dialer. All info is hardcoded in PLAYER_INFO โ€” edit the array to update.

Courses

Blueprint-style cards for all 7 courses (2 practice, 5 tournament). Each card shows Location, Par, and Designer in a spec-sheet format. Below that, a 2-column player grid shows each player's course handicap. Player names are navy; handicap values show "โ€”" until populated in COURSES[].players.

Flights

Arrival/departure info for all 8 players. Ben and Nate show "Driving." All other players have editable fields: Date, Time, Airport, Flight # for both arrival and departure. Data stored in Supabase flights table. Permissions: each player can edit their own row; Owen (p7) can edit all rows. Tap a cell to edit inline.

Hall of Quotes

Quotes stored in Supabase quotes table. Any player can add a quote with attribution and context. Quotes persist year to year. Commissioner can delete quotes.

Archives

Three sections: Trip History cards (2022โ€“2026), All-Time Standings table, and Handicap History table. All data is hardcoded in TRIP_HISTORY, ARCHIVE_STANDINGS, and ARCHIVE_HDCP arrays. Must be manually updated after each trip. 2026 trip shows as TBD with tbd:true flag โ€” excluded from standings until updated.

Standings sort order: trips (most first) โ†’ wins โ†’ ties โ†’ losses (fewest first).

App Info

Contains: Add to Home Screen instructions (expandable, with screenshots), Troubleshooting / cache clearing instructions, About section (version, credits), and Commissioner Docs link (visible to Owen only).

Deep link: cticlubhouse.com/#appinfo opens App Info directly and auto-expands the iPhone install instructions.

08

Real-Time & Caching

Supabase Real-Time

The app subscribes to all changes on scores, drinks, manual_drinks, and messages tables via WebSocket. Any score entered by any player on any device updates everyone's scorecard within ~1 second. The connection status dot in the app header shows green (connected) or red (disconnected).

Local Storage Fallback

All scores are also saved to localStorage on the device. On app load, local data renders instantly while Supabase data loads in the background. Supabase always wins on conflict โ€” it overwrites local with server truth on every load.

Service Worker & PWA Caching

The app uses a service worker (sw.js) that caches the HTML, icons, and manifest. Cache version is currently cti-2026-v7. When a new version is deployed:

  • The new SW installs immediately (skipWaiting)
  • Takes control of all open tabs (clients.claim)
  • The page detects the controller change and reloads automatically
  • Old cache is deleted on activate

To force a cache bust on deploy: bump the version string in sw.js from cti-2026-v7 to cti-2026-v8, etc.

Deploy Workflow

GitHub repo: ochamberlin7/cti-clubhouse โ†’ Netlify auto-deploy on commit (~30 sec). Alternatively, drag-and-drop a zip to Netlify deploys page (costs zero build credits). When dragging, always include all 4 files: index.html, sw.js, manifest.json, apple-touch-icon-2.png.

โ›ณ Pre-Trip Checklist

~1 Month Before (when handicaps stabilize)
Enter course handicaps for all 7 courses in COURSES[].players
Pre-calculate to 90% of USGA course handicap. Do NOT enter raw index. Enter final adjusted value per player per course.
Set SUPPRESS_SHARED_STROKE_DOTS = false
Flip from true to false to re-enable stroke dots once handicaps are populated
Update player handicap indexes in PLAYERS and PLAYER_INFO arrays
Both arrays need updating. hdcp field is currently null for all players.
Assign team rosters in PLAYERS array (team: 1 or team: 2)
Currently all set. Update TEAM_NAMES from "Team 1"/"Team 2" to actual team names
Update TEAM_NAMES = {1:'Grandmas', 2:'Warthogs'}
Currently "Team 1" / "Team 2" as placeholder
~1 Week Before
Confirm tee times and update SCHEDULE, TODAY_SCHEDULE, and ROUND_WINDOWS if any changed
ROUND_WINDOWS drives the live banner pre-round timing โ€” must match actual tee times exactly
Verify pairings in PAIRINGS object match final team assignments
Each round has 2 pairings. t1 = Team 1 players, t2 = Team 2 players
Confirm stroke indexes (SI) are correct for each course in ROUNDS[].index
Pull from the official scorecard for each course
Update ARCHIVE_HDCP with current handicap indexes for all 8 players
Day of Trip / After
Run SQL in Supabase to clear any test scores before real play begins
DELETE FROM scores; DELETE FROM drinks; DELETE FROM manual_drinks;
After trip: update ARCHIVE_STANDINGS with 2026 results
Increment trips count, add W/L/T for each player, update bestHdcp if improved
After trip: update TRIP_HISTORY 2026 entry โ€” set winner, winnerType, tbd:false
After trip: add 2026 handicaps to ARCHIVE_HDCP (the null column for '26)
Bump app version in App Info and ARCHIVE_HDCP_YEARS for next year
Any Time You Deploy
Bump SW cache version in sw.js (cti-2026-v7 โ†’ v8, v9, etc.)
Forces all devices to clear old cache and load the new version
If drag-and-drop deploying: include all 4 files in the zip
index.html + sw.js + manifest.json + apple-touch-icon-2.png โ€” drag-drop replaces entire site

CTI History

Archives

Commissioner

Tournament Purse

Set Dinner Bill

Enter the total welcome dinner bill. The losing team splits it evenly โ€” 4 ways.

$
Welcome to
Couch Tour Clubhouse
Who are you?