whereis.cam Event Model
Event Model · reverse-engineered from code

whereis.cam

Mates subscribe, Home Assistant notices Cam walk into a Brunswick pub, the radar confirms the visit after five minutes, and everyone on the list gets an email and a push. Cam can hide, fake or reveal his location from a password-protected dashboard.

Source: c-mco/whereiscam @ 1da200d (26 Oct 2026) Go · SQLite · Home Assistant REST · Resend · Web Push

The board

The app isn't event sourced. These events are the state changes the code already makes implicitly: rows inserted or flipped in SQLite, in-memory flags toggled, emails and pushes sent. Each column is one slice. Dashed blue lines show which events a view reads.

Screen Automation External event Command View Event

Scroll the board sideways. Tap a column to jump to its slice and specs.

What the model shows about the code

Laying the timeline out exposed a few places where the board has a gap or the code disagrees with itself. File references are to the commit above.

  1. Visit history has no source

    A pub_visits table with arrival, departure and duration columns is created in storage/db.go, but nothing writes to it. Cam Left Pub only resets an in-memory flag, so a "Cam's pub history" view has nothing to project from.

    Persist Cam Arrived At Pub and Cam Left Pub; visit history, durations and a "regulars" leaderboard become plain projections.

  2. A restart re-announces the current visit

    The open visit (lastPubState in handlers.go) and both 3-hour cooldowns live in memory. If the server restarts while Cam is at the pub, the first poll sees a "new" arrival and the cooldown has been forgotten, so every subscriber is alerted again. Admin sessions and login lockouts reset the same way.

    Read the open visit and last alert from stored events on startup.

  3. The cooldown rule is narrower than the README says

    The rule is copied into alerts.go and push.go, and each copy remembers only the last pub alerted. Pub-hopping The Vic → Foreigner → The Vic inside three hours alerts three times. The README describes it as a per-visit cooldown.

    Decide the rule (per pub, or per evening), write it once as a spec over Arrival Alert Sent, and share it between channels.

  4. Override history is overwritten

    Stealth, cheeky and manual-pub modes are five key/value rows in app_settings. Each change overwrites the last, so there's no record of when Cam went dark or what he claimed.

    The four override events already carry everything needed; append them instead of overwriting.

  5. Unsubscribe is more fragile than documented

    The README promises RFC List-Unsubscribe headers, but SendEmail never sets the Headers field. Unsubscribing is also a plain GET on /unsubscribe?token=…, so mail-security link scanners that pre-fetch links can trigger Email Unsubscribed on a subscriber's behalf.

    Send the headers (with List-Unsubscribe-Post) and make the page confirm with a POST.