Tender

Tender is a race-day board that pairs sailboat skippers who need crew with people who want to race. We’re building it for one sailing club, where it will run as an invite-only pilot.

The problem

At Hoover Sailing Club, boats that need a crew go short-handed or stay on the trailer most race days, because a skipper and a willing crew never found each other. The club had already tried a shared chat channel, and it died: the people who needed it were never in it, nobody kept it current, and nobody could see who was still unmatched. Meanwhile, adults who had finished a learn-to-sail course had no route onto a race boat.

That’s the account of the club’s coach, not a count. The club keeps no record of boats that didn’t sail for want of crew, so this page claims no number for it.

What we built

A board that stays current without anyone tending it. Every race date of the season is on it before anyone posts. A skipper posts a need, crew say they can, the skipper accepts one, and only then are contact details shared, between those two people and nobody else. If nobody suitable answers, the search widens on its own as race day gets closer.

What it proves

The privacy rule lives in the database, not only in the app: a phone number is visible to the two people in a match and to nobody else, so going around the app doesn’t get around the rule. Every one of those database rules has a test that fails before it passes, run against a real Postgres database.

The two riskiest technical bets were written down with the evidence that would kill them, then tested on the real project before they were relied on. There are no usage numbers here yet: the pilot hasn’t run a season, and this page won’t estimate one.

Sailors at Hoover looking for the board rather than the engineering can go straight to tender.madcowsailing.com.

Why it matters: who sees what is enforced in the database, not only on the screen.

A race day on Tender's board, in demo data: Sunday 25 October at 1:00 PM, Sunday Series 6, 21 crew can sail. Fixture Boat 1 (Thistle) needs crew at rung 1, green, with 21 candidates and 3 answered, and Fixture Boat 11 (Flying Scot) is crewed by Fixture Crew 11 with Fixture Crew 7.

Have a problem like this in your business?

Book a free 20-minute call

If you hire us for a build within 60 days, the full $1,500 counts toward it.

The technical detail, for developers and agencies

Each figure was read from the project’s records on 12 September 2026.

  • Built by: one person. Discovery, architecture, code, and the coming pilot at the club.
  • Stack: Next.js and TypeScript, Supabase Postgres with row-level security as the authorization, and pg_cron for the ladder clock.
  • Timeframe: August 2026 to now. Still in progress.

The problem, in detail

At Hoover Sailing Club, crewed boats (Thistles, Flying Scots, Interlakes) go short-handed or stay on the trailer most race days because a skipper and a willing crew never found each other. What would settle how many is a dock tally kept through the first month of the 2027 season, and that is the test this project has agreed to be judged by.

Matching today happens on the dock or by a text from the coach. The club had already tried the obvious fix, a shared chat channel, and it died of three things: the people who needed it were never in it, nobody owned it so it went stale, and nobody could see who was still unmatched. Skippers refusing to post was explicitly not one of them, which removed the hardest design constraint before it was ever imposed. The unmatched supply is the adult Learn-to-Sail graduates who finished a course and have no route onto a race boat.

This is a two-sided board at about ten crewed boats, which is the shape most likely to die of cold start: skippers post only when desperate, graduates look only when hopeful, and at that size the two moments rarely coincide.

What we built, in detail

A race-day board that is always current without anyone curating it. Every race date of the season exists before anyone posts, so the board is never blank, only unclaimed. A skipper posts a need against a date with a boat class and the minimum competence they will take; crew keep a self-rating and a list of hulls they will sail, and mark the days they are free. A crew answers a post with one tap, the skipper accepts one of those who answered, and contact details are exchanged only at that point.

The engine is a pure function (post, pool and the current time in, an open rung and a ranked list of candidates out) with no database and no clock of its own. That is what makes it testable at all, and its test was the first real test in the repository, proven able to fail by mutation before it was trusted.

Authorization is row-level security in Postgres rather than checks in the application, because the rule that matters is a property of the data: a phone number is visible to the two people in a match and to nobody else. A bypass of the app is therefore not a bypass of the rule. Every policy has a failing-then-passing case in a test harness that runs a real Postgres in CI, and that harness’s one blind spot, that it grants more than the hosted platform does, is written down in the repository rather than discovered later.

The notification is the product and the board is the record. A post reaches the crew on its current rung by push and by email; the clock that widens a post runs inside the database on a schedule, because the host’s own scheduler fires once a day with an hour of slop and the engine’s boundaries are two days and one day before the race. Sign-up is gated by an invite code checked on the server, so the pilot will stay closed to one club.

A decision we’d defend

The match ladder is a search order, not a filter. It colours how far the search had to relax, and it never hides anyone.

Concretely, every crew sits on one of three rungs relative to a post: rung 1 if they will sail that class and rate at or above the skipper’s minimum, rung 2 if they clear the minimum but not the hull, rung 3 if they rate below it. The post itself is open to a rung, and it widens on emptiness or the clock, whichever comes first: down a rung when nobody available sits on or above the current one, and no later than two days before the race for rung 2, or one day before for rung 3. The colour on the board is that open rung. Rung 3 is the floor, and a post that reaches it returns whatever it has, possibly nobody.

The part we’d defend hardest is what the ladder does not do. A crew on a better rung is never dropped because the post widened, and a crew on a worse one is never removed from the list: they are ranked below, in colour. That is what makes a wrong self-rating a warning rather than an exclusion, and self-ratings will be wrong: the scale is four levels a person picks for themselves, and modesty and bravado both misreport it. A filter would turn either into silence, and silence on a two-sided board is indistinguishable from nobody being there.

What it rejected, and why:

  • Coach-set competence rungs. Recommended in the discovery session and declined: it is work the coach does forever, and it only ever covers the people the coach taught. The project’s own stated purpose is to make the matching survive without the coach, so an option that deepens the dependency on them fails on its own terms.
  • Weight against the boat’s target. The most physically accurate signal for a dinghy, and unusable: people will not post it, and a blank field reads as refusal rather than as missing data.
  • The ladder as a filter. The version where a rating below the minimum removes you from the skipper’s list. Rejected because a wrong self-rating then excludes rather than warns, and the person it excludes is exactly the graduate this board exists to get onto a boat.
  • Multi-club matching from day one. Deferred rather than killed. It trades the one reach channel the owner actually controls, the club’s own class roster, for a committee’s yes, and it makes the project’s central claims uncheckable without a second club to check them in.
  • Availability only, with no ladder at all. The first answer given during discovery, and reversed at the narrowing gate: a board that only says who is free leaves the skipper to do the matching, which is the work that was already failing.

The cost is honest, and it is paid by the reader rather than the engine. A colour on a board carries meaning a first-time user has to learn, and nothing on the screen explains a rung until they ask. The email budget on the free tier is a hundred a day, which is what forces notifications to the current rung only rather than to the whole pool, so a crew two rungs down learns about a post when the ladder reaches them, not when it is posted. Both are deliberate, and both are the kind of thing that looks like an oversight from the outside.

Outcome

Being readied for an invite-only pilot at one club, deployed at tender.madcowsailing.com. As read on 12 September 2026, the board, the profiles, the posting and answering, the accept that forms a match and reveals contact details, the rung notifications and the clock that steps a post down were all built and deployed. The match thread, the morning-of confirm that catches a no-show, and the admin’s read of the season metric were specified and not yet shipped.

Two architectural bets were written down with the evidence that would kill them, and both were then tested rather than assumed. The database scheduler the ladder clock depends on is not documented as available on the free plan; it was enabled on the real project and watched fire every minute for nine minutes before the decision was allowed to stand. The authorization model was to be abandoned if the contact-on-match rule needed an escape hatch to express; it did not, and the policy that enforces it reads the match table directly.

The board was deliberately held empty of invitations until race dates were seeded. The failure metric the pilot will be judged by is fewer than one match per race day, averaged over a season.

Book a free 20-minute call

If you hire us for a build within 60 days, the full $1,500 counts toward it.

Run an agency? Send us a project

Next case study: Club photo site