ghostguild-org/docs/superpowers/specs/2026-04-14-board-classifieds-design.md
Jennie Robinson Faber 707447fc88 spec: board classifieds redesign
Replace passive tag-matching with active classifieds posts.
Corkboard/zine card UI, Slack topic channel integration,
admin channel mapping, simplified profile board section.
2026-04-14 15:09:40 +01:00

198 lines
6.8 KiB
Markdown

# Board Classifieds Redesign
## Overview
Replace the Board's passive tag-matching system with an active classifieds board where members post what they're seeking and offering. Posts are the single source of truth for board presence. The UI follows a corkboard/zine card layout. All communication happens on Slack via curated topic channels.
## Goals
- Give members a reason to browse and return to the Board
- Make the Board feel like a BBS — fun, personal, alive
- Push all conversation to Slack (no in-app messaging)
- Replace the abstract tag-state system with concrete, human-readable posts
## Design Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Visual style | Corkboard / zine cards | Fits existing design language, gives each post personality |
| Posts vs matching | Posts replace tag-matching entirely | Single source of truth, simpler mental model |
| Post lifecycle | Evergreen until removed by author | Simple, member-managed |
| Posts per member | Unlimited | Community will self-regulate |
| Slack integration | Web URL links to curated topic channels | `gammaspace.slack.com/archives/{channelId}` — tested, works reliably |
| Slack deep links | Protocol (`slack://`) and app links do not work | Tested — only web URL format opens the correct channel |
| Channel management | Admin-managed, curated set with tag mapping | Admin UI to map cooperative tags to Slack channels |
| Unmapped tags | No Slack link shown | No fallback channel |
| Visibility | All members see all posts | Behind `members-auth` middleware |
| Migration | None needed | Pre-launch, test data only |
## Data Model
### New: `BoardPost`
```
author ObjectId, ref Member, required
title String, required, max 120
seeking String, optional, max 500
offering String, optional, max 500
note String, optional, max 300
tags [String] — slugs from cooperative tag pool
createdAt Date
updatedAt Date
```
Validation: at least one of `seeking` or `offering` is required.
### New: `BoardChannel`
```
name String, required — display name (e.g. "Structure & Governance")
slackChannelId String, required — Slack channel ID (e.g. "C09DDGZGXAP")
tagSlugs [String] — cooperative tag slugs mapped to this channel
createdAt Date
updatedAt Date
```
### Member Model Changes
**Remove:**
- `board.topics` (array of tag/state objects)
- `board.details`
- `board.offerPeerSupport`
- `board.availability`
- `board.personalMessage`
**Keep:**
- `board.slackHandle` — author's Slack identity, shown on posts
- Privacy toggle for Slack handle visibility
## Board Page
### Layout
Corkboard card grid. 2 columns on desktop, 1 column at ≤1024px. Newest posts first.
### Header
- Page title "Board" with post count subtitle
- "+ New Post" button
- Tag filter drawer (existing pattern — toggleable, filters posts by tag)
### Post Card
Each card displays:
- **Type indicator:** SEEKING (gold) / OFFERING (green) / SEEKING ↔ OFFERING (ember) — derived from which fields are filled
- **Title** — prominent, Brygada 1918
- **Seeking text** — if present
- **Offering text** — if present
- **Note** — personal touch, slightly different visual treatment
- **Tags** — dashed-border pills
- **Footer:** author avatar + name + circle badge
- **Slack link:** "Discuss on Slack →" linking to mapped channel. Only shown if post's tags map to a channel. Uses `https://gammaspace.slack.com/archives/{channelId}`. If tags map to multiple channels, use the first match.
### New Post Form
Inline at top of the Board page (not a modal). Fields:
- Title (required, 120 chars)
- Seeking (optional, 500 chars)
- Offering (optional, 500 chars)
- Note (optional, 300 chars)
- Tags (multi-select from cooperative tag pool)
Validation: at least one of seeking/offering required. Form appears on "+ New Post" click, collapses after submission.
### Empty State
Friendly prompt to be the first to post, with link to create.
## Profile Board Section
Replaces the current cooperative tag selector, details textarea, and peer support section.
### Shows
- List of member's active posts (compact card previews)
- Edit and delete actions per post
- "+ New Post" button (navigates to Board page or opens same inline form)
- Slack handle setting (identity-level, not per-post)
- Privacy toggle for Slack handle
### Removes
- `CooperativeTagSelector` three-state tag picker
- Details textarea
- Offer Peer Support toggle + conditional fields (availability, personal message)
### No Posts State
Prompt to visit the Board and post something.
## Admin: Board Channels
New admin page for managing Slack channel mappings.
### UI
- List of board channels showing: display name, Slack channel ID, mapped tags
- Add / edit / remove channels
- Tag mapping: multi-select from cooperative tags
- Unmapped tag indicator: shows cooperative tags not yet assigned to any channel
### Behavior
- Admins create channels in Slack manually, then register them here by pasting the channel ID
- Frontend uses the channel list to build Slack links on post cards
## API Routes
### New
| Method | Path | Auth | Purpose |
|--------|------|------|---------|
| GET | `/api/board/posts` | member | List all posts, newest first. Tag filtering via query params. Populates author name/avatar/circle/slackHandle. |
| POST | `/api/board/posts` | member | Create a post. Validates at least one of seeking/offering. |
| PATCH | `/api/board/posts/:id` | member (own post) | Edit a post. |
| DELETE | `/api/board/posts/:id` | member (own post) | Delete a post. |
| GET | `/api/board/channels` | member | List channels with tag mappings (for building Slack links). |
| GET | `/api/admin/board-channels` | admin | List channels for admin UI. |
| POST | `/api/admin/board-channels` | admin | Create channel mapping. |
| PATCH | `/api/admin/board-channels/:id` | admin | Update channel mapping. |
| DELETE | `/api/admin/board-channels/:id` | admin | Remove channel mapping. |
### Remove
| Path | Reason |
|------|--------|
| `GET /api/board/suggestions` | Replaced by posts |
| `PATCH /api/members/me/board` | Board profile fields removed (slackHandle stays on existing member profile patch) |
## Components
### Stays (repurposed)
- `CooperativeTagSelector` — simplified to a plain tag picker (no three-state toggle) for use in post creation form
### Goes
- Match-card UI on Board page
- Peer support section on profile page
### New
- `BoardPostCard` — the corkboard card component
- `BoardPostForm` — inline creation/edit form
- `BoardPostList` — grid layout for post cards (used on Board page and profile)
- Admin channel management components
## Composables
### Remove
- `useBoard` (the old `getSuggestions` wrapper)
### New
- `useBoardPosts` — CRUD for posts, tag filtering
- `useBoardChannels` — fetch channel mappings, resolve tag→channel for Slack links