Skip to content

The Big Rewrite#67

Draft
tomjn wants to merge 77 commits into
masterfrom
rewrite
Draft

The Big Rewrite#67
tomjn wants to merge 77 commits into
masterfrom
rewrite

Conversation

@tomjn

@tomjn tomjn commented Jun 17, 2026

Copy link
Copy Markdown

This completely rewrites the codebase with a modern stack, and brings in a tonne of polish and long requested features

tomjn added 30 commits June 9, 2026 16:42
Also fix res.sendFile to resolve CLIENT_DIR to an absolute path so it
works when the env var is passed as a relative path.
…me picker, Vote/Watch join prompt, HM red brand, pointer cursors, drop stddev
…ine numeric-only results, collapsible structured history, start-new-vote, deck previews; fix join name cap + dev SPA 503
…ces participant cards with uncoloured result cards; relayout reveal (cards > stats > start-new-vote > deck); own vote highlighted locally; fix deck menu offscreen
tomjn added 30 commits June 17, 2026 12:59
Lint and tests previously failed on a clean checkout because @hmpp/shared
resolves via its exports map to dist/, which only exists after a build.

- server lint: typecheck via tsconfig.lint.json with a paths mapping to
  the shared source entry, so no prior build is needed
- server/client tests: vitest alias @hmpp/shared to the shared source

Build still produces dist for production; lint/test no longer depend on it.
The platform's EFS access point creates /data owned by 33:33 (mode 755)
with no posix_user remapping, so the container must run as uid 33 to write
there. Our custom 'app' system user had a different uid, so the boot
writability check failed with EACCES. Verified locally: container runs as
www-data (33), passes the /data write guard, binds port 80, serves 200.
The custom non-root user couldn't bind port 80 (Fargate keeps
ip_unprivileged_port_start at 1024) nor write the EFS /data mount. Every
working tool on the platform (pitch-deck-generator, human-bot, letter-clash)
runs as root: root binds 80 natively and writes /data since EFS doesn't
squash root. Drop the USER directive to match.

Verified locally under --sysctl net.ipv4.ip_unprivileged_port_start=1024
(Fargate's behaviour): binds port 80, serves 200.
- crossfade route changes via the View Transitions API (lobby <-> room)
- entrance motion for role-select, joining, results, and reset button
- fix confetti pieces parked at the top (animation fill-mode both)
- cap recent-rooms column height with internal scroll; centre left column
- show last-active/opened relative time per recent room (server lastActivityAt)

All motion gated behind motion-safe/prefers-reduced-motion.
- AutoHeight wrapper grows/shrinks the room table over 200ms when the
  voter cards swap for the larger revealed cards, instead of snapping
- clip overflow only while the height animates, so card hover lifts and
  shadows aren't clipped at rest
- waiting/observer participant cards now use a neutral deck-matching
  border + soft colour tint rather than a hard saturated outline; the
  bold filled card stays reserved for the voted state
Replace the silently-reassigned "admin" with an explicit facilitator that
fixes the historical stuck-room failure mode.

- Facilitator persists across reconnects and is never auto-reassigned: an
  absent holder's seat becomes claimable and they reclaim it on return.
- Reveal and reset are universal (any participant), so a room never gets
  stuck waiting on one person; eject/deck/voter-override stay facilitator-only.
- Reveal sweep: on reveal, voters who didn't vote become observers (flagged
  autoDemoted) so the next round auto-reveals cleanly; demoted users get a
  rejoin nudge, others a toast.
- Manual reveal has a 10s post-round-start cooldown (auto-reveal exempt) so a
  hasty reveal can't sweep still-voting people.
- Surfacing: facilitator dot in the roster (with accessible label), header
  menu for deck/eject/pass, facilitator-change + demotion toasts.
- Reveal button only shows when there's something to reveal; reset hidden
  when nothing to reset.

Also repairs a pre-existing stale RoomStatus test fixture.
- Replace the in-body "Room: <slug>" heading with a small clickable slug in
  the header that copies the room link.
- Lay the header out as logo / centered slug / controls so the slug sits in
  its own flexible column and truncates instead of overlapping the icons.
- Collapse facilitator controls (deck, eject, pass) to icon-only triggers on
  mobile, with labels returning at sm+; hide the wordmark below sm.
Crossfade the participant glyph on role/vote change, grow/collapse the
deck slot with a symmetric enter (expand then fade) and exit (fade then
collapse), and center the room slug via a 3-column header grid.
The deck source was reordered XS->XL ascending in 104c29a but the test
still expected the old descending order, leaving CI red.
Server emits 'server:maintenance' on SIGTERM/SIGINT and drains gracefully so clients show a 'back soon' toast before the socket drops; Socket.IO auto-reconnect then resumes the session.

Eject-on-leave now defers removal by a grace window (EJECT_GRACE_MS, default 30s): a tab that drops and reconnects in time keeps its seat and vote; one that never returns is reaped.
…banner

The notice now uses an infinite duration with a stable id and is dismissed on the socket 'connect' event, so it stays for the whole downtime instead of auto-hiding after 4s.

Bumped the Toaster offset so the toast clears the fixed ConnectionStatus banner rather than overlapping it.
…rtifacts

Ignore *.tsbuildinfo and nested data/ dirs (runtime SQLite DB).
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