When a club has no curated routes or a chat channel has no messages, the data layer
returned fixture content with no indication it was sample data, so riders could mistake
MotorSignal's "Coastal Marshes" route or canned chat messages for their club's real data.
Flag fixture-sourced content and label it in the UI:
- Add isExample to ClubRoute and ChatMessage; set it on every fixture fallback path
(empty Firestore collection/channel and the dev demo preview).
- Founder Routes: amber "Examples" count, an explanatory banner, and a per-card "Example"
badge when the routes shown are samples.
- Founder Chat: an "Example thread" pill (instead of "Live Connected") and a banner when
the only messages are examples, so the header never claims a live conversation that
does not exist.
Tests: example-labelled routes render the banner/badge/count; example-labelled chat
renders the banner and "Example thread" pill and does not claim "Live Connected".
Existing route/chat tests (real data, no isExample) remain green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Fix RenderFlex overflow at short landscape breakpoint (640x320) by scaling center controls in ResponsiveDashboardLayout and clamping LeanAngleIndicator bounds
* feat(clubs): enable admin group ride governance
* feat(clubs): add secure member ride discovery
* fix(clubs): protect meeting location in ride discovery
* feat(group-rides): secure club join moderation
* test(clubs): update ride discovery expectations
* test(founder-portal): update rides governance expectations
* fix(group-rides): resolve pre-merge findings on join moderation and discovery
- Block participant hard deletes for accepted status and organizer role for all callers
- Support atomic accessUids removal on invitation decline in firestore.rules
- Restrict mutual-block checks to approvals in GroupRideService, allowing decline of blocked requests
- Implement cursor-paginated candidate scanning with block filtering in website discovery API
- Add comprehensive emulator, vitest, and unit tests covering all 5 findings
* fix(discovery): page candidates until 30 eligible rides collected or query exhausted
- Remove artificial 150 candidate scan ceiling in club rides discovery route
- Continue cursor pagination until 30 unblocked eligible rides are collected or upcoming schedule query is exhausted
- Add test verifying pagination continues past 150 blocked rides to collect all 30 eligible rides
---------
Co-authored-by: Developer <dev@example.com>
* feat(ops): implement production operations infrastructure dashboard (phase 1)
- Add backend read-only infrastructure metrics collector (CPU, RAM, swap, disk with 80%/90% thresholds, uptime, network cumulative totals, systemd service allowlist) using standard library only (no psutil).
- Register GET /api/v1/ops/infrastructure endpoint guarded by require_ops_roles('operator', 'owner').
- Add Next.js API proxy route /api/ops/infrastructure validating ops session cookie and forwarding to backend.
- Implement dark-surface OperationsInfrastructure component in website admin console with 30s visibility-gated polling and overlap prevention.
- Add comprehensive backend and frontend test suites (8 backend tests, 43 ops-experience tests).
* fix(ops): query internal website version endpoint defensively on verified port 3001
- Query internal website GET /api/version on verified production listener http://127.0.0.1:3001 (configurable via WEBSITE_INTERNAL_URL).
- Parse JSON defensively with a 4096-byte response bound and validate exact 40-char hex revision pattern.
- Add comprehensive tests for valid, missing, malformed, oversized, and unreachable version responses.
- Do not expose internal URLs or connection errors in API responses.
* fix(ops): map postgresql service to cluster unit postgresql@14-main and preserve health errors
- Map public logical service ID 'postgresql' to fixed systemd unit 'postgresql@14-main'.
- Reject direct systemd unit names and arbitrary service names.
- Preserve HTTP 5xx responses as degraded on /api/health before root fallback.
- Add regression tests for postgresql unit mapping, API response name stability, and health 5xx preservation.
---------
Co-authored-by: Developer <dev@example.com>
Add the disabled Founder Portal Club Rides scaffold aligned with the live GroupRide.clubId domain.
Keep production discovery and actions disabled until a privacy-preserving read path and real management destinations are implemented.
- Gate ranks-roles management route on canManageSettings with safe
unauthorized state, matching sibling founder-management routes
- Enforce HTTPS image URL invariant for club logo/banner in the data
layer (validateClubImageUrl) and in Firestore rules, preserving
null/empty clearing