After createSubscription() calls checkMemberStatus(), isAuthenticated
flips to true and the <template v-else> branch unmounts, taking the
Teleport (and its overlay) with it. The authenticated 'You're already a
member' UI then showed for the 3-second pre-redirect delay, producing a
visible flash before navigateTo('/welcome') fired.
Teleport now lives at the root div alongside the v-if/v-else branches,
so the overlay stays mounted through the auth state transition and
covers the page continuously until the redirect.
"$50/yr" was ambiguous — could mean the $5 tier in annual mode or the
$50 tier in monthly mode. On /join the dropdown now shows both prices
("$5/mo → $50/yr") in annual mode. On the account page TierPicker
gains a subtitle slot; annual mode shows "$N/mo tier" beneath the
annual price so members recognize which tier they're on.
Radio-pair cadence selector (Monthly / Annual) added to the join form,
reusing the existing .circle-radio styling. contributionItems computed
reactively; all tier labels and the left-column price list update on
toggle. cadence submitted with the subscription payload. payment-setup
hardcoded to monthly (annual upgrades go through /join).
pending_payment now grants the same RSVP/peer-support capabilities as active,
and status banner/label copy is rewritten to be non-threatening ("Setting up
payment", "Paused", "Closed"). Aligns member-facing copy across the account
page with the capability model.
Extracts hasMemberAccess(member) in tickets.js and uses it across event
registration, ticket purchase, and series purchase flows so guest, suspended,
and cancelled records no longer count as members while pending_payment still
does.
Introduces /community-guidelines and /policies/{privacy,terms,[slug]} pages,
swaps the signup/invite checkbox from agreedToTerms to agreedToGuidelines,
adds Member.agreement.acceptedAt, and stamps the field when a Helcim
customer is created.
Non-members who register for an event now get a persistent identity:
with consent, a status:"guest" Member is upserted and an auth cookie is
set so the "You're Registered" state survives a page refresh.
Tiered auto-login matches passwordless-auth norms — auto-login is only
safe when the account holds no privileges:
- New email → create guest + cookie
- Returning guest → cookie
- Existing non-guest (active/pending/etc.) → attach ticket only, no
cookie, confirmation email includes a sign-in link
Guests are gated on status === "guest", so admin/middleware code that
keys on status === "active" naturally excludes them. Guests are also
treated as non-members for ticket pricing/validation to prevent picking
up member-only pricing on their second registration.
Members (and pre-registrants) hitting wiki.ghostguild.org were getting bounced
to /coming-soon with a "Pre-Register" link, even when the OIDC flow was
working correctly.
- Allowlist /auth/oidc-error, /auth/logout-confirm, /auth/logout-success,
and /verify in the coming-soon middleware so OIDC errors and main-site
magic links stop redirecting to the pre-register page.
- Raise OIDC Interaction TTL from 10m to 15m so it outlives the magic-link
JWT and legitimate members don't hit expired-interaction errors when they
click the email a few minutes late.
- Differentiate the "email isn't a registered member" response on the wiki
login route and show a dedicated "Not a member yet" state with a
pre-register link and contact email, instead of the misleading
"Check your inbox" that silently failed.
Delete uses findOneAndDelete with author match (no TOCTOU window);
existence check only runs on miss to distinguish 403 vs 404. Posts
list capped at 200. Drop unused resolveTagChannel and refreshParams;
route slack URL building through the composable's slackUrl helper.
Replace window.confirm with an inline Delete? / Cancel / Confirm flow on
post cards. Add focus-visible outlines, initials in avatar placeholders,
and promote post/form titles from h3 to h2 for heading order.
- Timezone: curated USelectMenu dropdown (app/config/timezones.js), preserves unknown saved values
- Profile save now uses useToast() for success/error; remove inline save banner
- Nav onboarding dot nudged down 1px for optical alignment with lowercase text
- Onboarding: skip a suggestion with POST /api/onboarding/track {skip}; member.onboarding.skipped map; does not affect graduation
- CirclePicker takes :saved-value so 'Current' badge stays until save completes
- PrivacyToggle is binary (USwitch labeled Private); member schema enum reduced to ['members','private']; zod coerces legacy 'public'
- New /member/payment-setup page: HelcimPay $0 verify + update-contribution, wired from account.vue via requiresPaymentSetup redirect
- Helcim portal: NUXT_PUBLIC_HELCIM_PORTAL_URL env + account.vue 'Manage billing in Helcim' link
- Migration script: scripts/migrate-privacy-public-to-members.js
- useBoardPosts: CRUD with useState('board.posts','board.loading')
- useBoardChannels: fetch + resolveTagChannel + slackUrl helpers
- useBoard.js removed (old suggestions wrapper); only app/pages/board.vue still imports it, will be rewritten in Phase 5
- Add Board to exploreItems in AppNavigation
- Update ecology.vue + connections.vue redirects to /board
- Rename all communityEcology refs to board in member profiles, dashboard, admin, onboarding
- Update API path /api/members/me/community-ecology → /api/members/me/board
- Renamed ecologyTagOptions, ecologyFilterTags, ecologyTagLabel → board* throughout refs, computed, helpers, and template
- Removed .filter-bar div (duplicate count display)
- Updated pageSubtitle to use filteredSuggestions.length so subtitle reflects active tag filtering
Model, schemas, API routes, activity log, and all server handlers
updated. Old ecology/ and community-ecology routes removed, new
board/ routes added. Tests updated and new board-suggestions tests
written (10 cases).
Merge the directory and ecology views into a single page with a
segmented toggle. Directory mode is public; ecology mode requires auth.
URL-driven view state (?view=ecology), collapsible tags drawer,
filter-state reset on mode switch, onboarding tracking, and responsive
breakpoints at 1024/768/375px.
- ecology.vue replaced with redirect to /members?view=ecology
- connections.vue updated to skip the /ecology hop, redirects directly
- Remove Ecology nav entry; Members covers it