Deduplicate tag validation and regex escaping into shared auto-imported
utils. Add tag validation to wiki patch/batch-tag routes. Remove
duplicate tags field from event schema.
Update CSS comment from "Community Connections" to "Community
Ecology" in member detail page. Docs, CLAUDE.md, and activity log
spec also updated (gitignored, local only).
Dashboard: replace "Peer Support" card and "Book a peer session"
quick action with community ecology links.
Welcome: replace "Peer Support" resource card with "Community
Ecology" heading and link to /ecology.
Members index: rename active filter tag from "Offering Peer
Support" to "Offering Support". The underlying filter still works
correctly (queries communityEcology.offerPeerSupport).
The Skills Exchange + Peer Support feature was replaced by Community
Connections on 2026-04-05, but several files and code paths were left
in place as backward-compat. None are reachable from the live UI:
- usePeerSupport.js composable: not imported anywhere
- PeerSupportBadge.vue: not imported anywhere
- peer-support.vue: stub redirect with no incoming links
- /api/peer-support.get.js: only consumed by usePeerSupport
- /api/members/me/peer-support.patch.js: same
- profile.patch.js offering/lookingFor write branches: profile form
no longer sends these fields (only writes communityConnections.*)
- PEER_SUPPORT_ENABLED/DISABLED activity types and renderers: only
written by the deleted peer-support.patch endpoint. The activityText
formatter has a fallback for unknown types so existing records
still display ("peer support enabled" with a generic icon).
Tests updated to drop peerSupportUpdateSchema coverage and the
offering/lookingFor passthrough assertion.
schemas.js cleanup deferred — concurrent communityConnections →
communityEcology rename is in flight in the working tree.
Page Layout Simplification — Member Area Full-Bleed Pattern.
Converges the member-area surface on a canonical PageShell + ColumnsLayout +
PageSection vocabulary, replacing 3 ad-hoc two-column implementations and ~12
hand-rolled flex-chain blocks. PageShell owns the flex chain so individual
pages can no longer break it; PageSection enforces symmetric padding so
asymmetric drift is structurally impossible.
Visual snapshot coverage was expanded BEFORE component changes (15 of the 26
authoritative snapshots are new in this branch), then 9 pages were migrated
one commit at a time. Hydration mismatch on auth-conditional UI fixed by
wrapping v-if/v-else chains in <ClientOnly>. SidebarLayout deleted.
463/463 unit tests + 26/26 visual regressions green.
Now that all member-area pages have migrated to PageShell +
ColumnsLayout, SidebarLayout has no consumers and can be deleted.
PageShell owns the flex chain, so the .dashboard-body wrapper on
member/dashboard.vue (flex: 1; display: flex; flex-direction: column;
min-height: 0) is redundant. Update stale SidebarLayout comments on
members/[id].vue to reference ColumnsLayout.
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.