Skip to content

Bug fixes and dev quality-of-life improvements#3

Merged
hashd merged 25 commits into
masterfrom
fix/presence-and-template-rendering
Apr 11, 2026
Merged

Bug fixes and dev quality-of-life improvements#3
hashd merged 25 commits into
masterfrom
fix/presence-and-template-rendering

Conversation

@hashd
Copy link
Copy Markdown
Owner

@hashd hashd commented Apr 10, 2026

Summary

  • Presence crash: Phoenix.Tracker.track/4 requires a PID — was passing a LiveView socket, fixed with self()
  • HEEx text interpolation: {expr} in text nodes renders as literal text in LiveView 0.20.x — converted to <%= expr %> across host, player, and activity feed views
  • Duplicate component IDs: ActivityFeed was mounted twice (desktop + mobile) with the same ID — consolidated to one instance with responsive CSS
  • Empty game name: empty string input now falls back to "Untitled Game" via non_empty/1 guard
  • Game name form: wrapped input_field in a <form> so phx-change fires correctly on debounce
  • Dev auth plug: auto-logins as dev@localhost when dev_routes: true, bypassing OAuth during local dev
  • Chore: added .elixir_ls to .gitignore, reorganized docs under docs/

Test plan

  • Join a game as player — no presence crash on mount
  • Host lobby renders game name, code, player count, interval, bogey limit, prize labels correctly
  • Player lobby renders code and player count correctly
  • Activity feed shows event text (picks, chat, system messages) without literal {expr} strings
  • Create game with empty name field — should default to "Untitled Game"
  • Local dev: navigate to any page without going through OAuth

hashd added 25 commits April 10, 2026 04:47
Full rewrite design covering: context-separated monolith architecture,
supervised game engine with crash recovery, player-initiated prize
claims with bogey system, magic link + OAuth auth, LiveView web UI,
REST API + Channels for native mobile apps, and cluster-ready scaling.
Key changes:
- Eliminate per-second timer broadcasts; use client-side countdown
- Write-through for critical mutations (prize claims, player joins)
- Define connection resilience (host disconnect, player reconnect)
- Define Moth.Game.Monitor responsibilities and rest_for_one supervision
- Add token lifecycle (expiry, rotation, revocation)
- Add chat specification (ephemeral, rate-limited)
- Fix deps: keep phoenix_html, defer ueberauth_apple, swap to bandit
- Add room code design with enumeration protection
- Add concrete test scenarios and load testing plan
- Downgrade cluster-readiness claims to honest assessment
- Add settings constraints (min interval 10s)
- Add edge case table and status enum mapping
Covers: project foundation, migrations, schemas, Board/Ticket/Prize/Code
pure functions with TDD, Auth context (magic links, OAuth, tokens),
game supervision tree, GameServer lifecycle, crash recovery, Game
context API, router/layouts/plugs, LiveViews, API controllers,
Channel, and integration tests.
Full redesign spec covering design system, all screens, accessibility,
error/loading states, and scoped backend additions. Reviewed by critic,
architect, and QA lead agents — all critical and major findings addressed.
Covers: design system foundation, UI component library, JS hooks,
backend additions, all screen redesigns, presence, reactions,
and accessibility pass.
…config

Add CSS custom property token system (light/dark), Tailwind darkMode class
config, Inter font via Google Fonts, animation keyframes with reduced-motion
support, connection status banner, and page loading bar.
… presence, board sheet, auto-scroll, auto-dismiss
…one, auto-strike cast

- Add prize_progress computation in sanitize_state (per-player, per-prize struck/required tuples)
- Add server_now to pick broadcast for client clock sync
- Add strike_out_async (GenServer.cast) for fire-and-forget auto-strike
- Add reaction handler with 1s rate limiting
- Add recent_games query (host_id, ordered by inserted_at)
- Add clone_game for rematch flow
- Fix monotonic time rate-limit default for chat and reactions
Save the requested path in session when require_authenticated_user
redirects unauthenticated users. Preserve it across session renewal
in log_in_user, and redirect to it after successful login via OAuth
or magic link.
…, countdown

New MothWeb.Components.Game module with redesigned components:
- ticket_grid/1: 3x9 grid with card wrapper, accessibility roles
- ticket_cell/1: four visual states (empty, unpicked, picked, struck)
- prize_chip/1: available/claimed/disabled states with progress display
- number_pill/1: called-number pill with bounce-in animation
- board/1: 9x10 board (1-90) with pick highlighting and ticket dot indicator
- countdown_ring/1: JS hook wrapper for countdown animation

Imported in moth_web.ex html_helpers. Resolved import conflict with
old GameComponents in play_live.ex (qualified call for claim_buttons).
Adds the real-time activity feed component used by both PlayLive and
HostLive. Uses Phoenix.LiveView streams for efficient DOM updates
(capped at 50 entries). Supports five entry types: pick, prize_claimed,
bogey, chat, and system. Includes filter tabs (All/Chat/Events), chat
input form, AutoScroll hook, and aria-live for accessibility.
… feed + reactions

Three-state player view: lobby (waiting room with game code, player
count, prize list), running/paused (two-column layout with ticket grid,
countdown, prize chips with progress, picked numbers, board with mobile
bottom sheet, activity feed, reactions bar), and finished (game over
with confetti, prize winners, back-to-home). Uses strike_out_async for
auto-strike, proper PubSub event handling with activity feed updates.
…d, activity log

Rewrite host_live.ex with three distinct states:
- Lobby: game code hero card with copy hook, live player count, player list
  (capped at 20 + overflow), settings summary, and start button
- Running/Paused: three-column command center with board + countdown (left),
  game controls + player leaderboard with near-prize alerts + prize tracker
  (center), and activity feed (right); responsive single-column on mobile
- Game Over: winners summary, game stats, play-again (clone) and back-home

Adds full PubSub handler set (pick, status, prize_claimed, bogey, chat,
reaction, player_joined, player_left) with activity feed integration.
Expand MothWeb.Presence with track_player/3, update_status/4, and
list_players/1 helpers. Integrate presence tracking in both PlayLive
and HostLive mounts, handle presence_diff broadcasts by re-listing,
and wire up away/online events from the Presence JS hook.
…cleanup old components

- Delete old game_components.ex (replaced by Components.Game)
- Improve ticket_cell aria-labels: "Number N, not called" / "called, not struck" / "struck" / "empty cell"
- Add aria-pressed on struck cells
- Add role="button" and aria-label on prize_chip (claim/won states)
- Add aria-labelledby on modal pointing to title element
- Change toast role to "status" with aria-live="polite"
- Add aria-label on badge for live/paused/finished variants
- Add animate-shake and animate-strike-ripple to reduced-motion overrides
Phoenix.Tracker.track/4 expects a PID as the first argument, not a
LiveView socket struct. Pass self() to get the LiveView process PID.
Replace {expr} with <%= expr %> for text content in templates.
LiveView 0.20.x only supports {} in tag attributes, not text nodes.

Also consolidate duplicate ActivityFeed live_component instances
(desktop + mobile) into a single instance to avoid duplicate ID errors.
Auto-logs in a dev user (dev@localhost) when dev_routes is enabled,
skipping the OAuth flow during local development.
non_empty/1 helper treats "" as nil so an empty name field still
produces "Untitled Game". Also wraps the name input_field in a form
so phx-change fires correctly on debounce.
@hashd hashd changed the title Fix presence crash and HEEx template rendering Bug fixes and dev quality-of-life improvements Apr 11, 2026
@hashd hashd merged commit a505821 into master Apr 11, 2026
@hashd hashd deleted the fix/presence-and-template-rendering branch April 11, 2026 13:24
hashd added a commit that referenced this pull request Apr 13, 2026
…validation

- Filter struck set per-ticket in prize claims to prevent cross-ticket fraud (#1)
- Filter prize progress per-ticket to prevent cross-ticket info leak (#9)
- Strip join_secret from sanitized state (#2)
- Filter REST show endpoint to only return requesting user's data (#3)
- Filter player_tickets_updated broadcast to target user only (#4)
- Add chat text length limit (500 chars) and validation (#13)
- Add reaction emoji allowlist (#14)
- Add max players per game limit (100) (#11)
- Add input validation for game creation params (#23)
- Remove inspect(reason) from error responses (#22)
- Store rich metadata in Registry for O(1) game listing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant