Wave-based onboarding makes the auto-invite + polling path obsolete.
- Removes SlackService.inviteUserToSlack — admins now send invites
through Slack's UI and flip the flag in our admin endpoint.
- Removes the slack_invite_failed admin alert + its detector. The
alert no longer has a meaningful trigger (we don't attempt invites).
- Archives server/utils/checkSlackJoins.js (and its test) under
_archive/ in case the polling pattern is needed again post-pilot.
- Deletes the Nitro plugin that scheduled checkSlackJoins on boot
+ hourly. Nothing in nitro.config / nuxt.config / package.json
registered it elsewhere.
- Drops the slack_invite_failed branch from adminAlerts.test; the
enum slug stays in adminAlertDismissal so historical dismissal
rows continue to validate.
notifyNewMember (vetting-channel notification) and findUserByEmail
(used by the auto-flag helper) are retained.
a11y (main.css):
- Nuxt UI's default placeholder color (text-dimmed = #a6a09b) failed WCAG
AA contrast on cream (2.43:1) and white (2.58:1) backgrounds, blocking
axe checks on /member/profile (timezone) and /admin/events/create
(tags). Override [data-slot="placeholder"] globally to var(--text-dim)
(#5a5040), comfortably above 4.5:1 on both surfaces.
auth.spec.js (logout):
- Same hydration race as the board/admin-board-channels click tests:
/admin's sidebar Sign-out @click handler isn't bound when Playwright
fires the click immediately after admin-tag visibility, so the click
no-ops and waitForResponse for /api/auth/logout times out.
- Add waitForLoadState('networkidle') after goto so hydration completes
before the click.
join-flow:
- Form now requires Community Guidelines agreement; tests check the
checkbox before expecting submit to enable.
- Contribution input is a numeric field with preset chip buttons, not a
USelect with $0/mo options — fill the input directly.
- Success state lives in SignupFlowOverlay ("Welcome to Ghost Guild!");
no .success-box exists. Match by heading instead.
- Inline .error-box renders OUTSIDE <form>, so duplicate-email assertion
uses .signup-flow-overlay .error-box (which is the user-facing error).
member-profile:
- "How you appear to other members" copy was retired; replace with the
stable "Show in Member Directory" structural label.
- Add waitForLoadState('networkidle') after goto for ClientOnly auth
hydration so "Edit Profile" reliably appears within timeout.
board:
- Add waitForLoadState('networkidle') after goto so the action-bar's
"+ New Post" click handler is bound before the test clicks.
- Submit button is named exactly "Post" — disambiguate from "+ New Post"
buttons with { exact: true }.
- Delete is a two-step in-card confirm (Delete → Confirm), not a native
browser dialog; drop the page.once('dialog') listener.
admin-board-channels:
- Channel name placeholder is "e.g., coop-formation" (no leading #).
- Slack Channel ID input only appears in the Edit modal (v-if="editingId"),
not on Create — Slack channel is auto-created server-side. Drop the
slack ID fill from the Create step.
- Add waitForLoadState('networkidle') before opening the modal.
Vue hydration silently drops class attribute updates when SSR and client
render different branches of a v-if chain — per the project's Auth SSR
Pattern, useAuth is client-only and server always renders unauthenticated,
so PageHeader (v-else branch) was rendering inside a leftover .loading /
.loading-state div from the v-else-if branch. On mobile that div was
being masked by the visual-test commonMasks (.loading-state), producing
a large fuchsia block in the snapshot.
Wrapping the v-if/v-else-if/v-else chain in <ClientOnly> ensures the
server renders nothing for the auth-gated content and the client performs
a clean first render, matching the pattern already used in dashboard.vue.
Also update admin-dashboard-desktop for minor anti-aliasing drift.
Replace .activity-page wrapper + SidebarLayout with PageShell +
ColumnsLayout cols="events-sidebar". Delete the now-redundant
flex-chain CSS that PageShell owns. Adds .loading-state to the
visual mask list to handle the connections-mobile race between
the loading and loaded states.
Wrap members directory page in PageShell. Also expand visual mask
selectors to cover .filter-bar, .skills-bar, and .connections-section
because filter content varies based on dynamic tag/topic state and
async fetch ordering. Rebaselines several existing snapshots that now
mask wider regions but capture the same structural layout.
Replace outer div.connections-page wrapper and explicit PageHeader with
PageShell component. Update connections-mobile-auth snapshot to match
the stable full-suite render state (filter bar absent when test admin
has no cooperative topics configured).
Add PLAYWRIGHT_PORT env var to playwright.config.js so a worktree can run
its own dev server on a different port without disrupting the main dev
server. Rebaseline connections-mobile-auth which had drifted from the
suggestions data state captured during Phase 1.
Add about to authenticatedMobilePages to capture an authenticated baseline
needed for regression detection during the Phase 3.5 about.vue migration.
Rename all auth-mobile snapshots from *-mobile to *-mobile-auth to avoid
name collision with the public loop's about-mobile snapshot.
Adds 13 new visual regression baselines:
- Public: about (desktop + mobile), members (desktop + mobile)
- Authenticated desktop: member-account, member-activity, connections,
admin-dashboard, members-detail
- Authenticated mobile: member-dashboard, member-profile,
member-account, connections
Switches to a single serial test.describe with a beforeAll that logs in
once and saves the auth cookie via storageState. This avoids repeated
/api/dev/test-login calls that exhausted the dev server's MongoDB
connections under parallel execution.
Masks added: .tl-time, .stat-val, .item-date, .mc-avatar, .cc-avatar,
.profile-avatar, .filter-count — covering activity timestamps, stat
values, member join dates, avatars, and member counts.
- Add `middleware: 'auth'` to member/profile.vue (was missing)
- Harden loginAsAdmin helper to wait for networkidle after redirect so
auth-init plugin and admin middleware finish before tests navigate
- Regenerate visual baselines to reflect updated profile page UI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add aria-labels to form controls (selects, checkboxes, switches), set
html lang attribute and page title, fix color contrast for --candle-dim
and --text-faint tokens, underline inline links, remove opacity hack.
Harden dev login endpoints with atomic findOneAndUpdate and tokenVersion
in JWT. Update Playwright timeouts and E2E test helpers.