Communications Hub My Workspace
Communications Hub - My Workspace
Route / navigation: Browser path `/my-workspace` (PageView my-workspace). Tool selection: Zustand `workspaceTool` (WorkspaceTool in src/store/types.ts). Rendered by WorkspacePage in PageRouter.tsx.
Overview
The Communications Hub is accessible via the My Workspace sidebar item. It provides direct messaging, calendar, notes, contacts, board meetings, and related tools, with role-based access and (for messaging) real-time updates.
Feature Summary
- Sidebar Item: "My Workspace" (directly below Dashboard; visible to all users, tools inside are paywalled for free tier)
- Tools (7 total):
- Messenger: Direct messaging between organization members (Plus+)
- Video Conferencing: Schedule and manage video meetings with AI transcription (Plus+)
- My Files: Secure file sharing with team and external contacts (Plus+)
- Contacts: Manage business contacts and partners (Free)
- My Calendar: Schedule events, manage availability, share public booking links, and open external group polls (Doodle) from the toolbar (Free). Event times are rendered timezone-aware from
workspace_events.event_date+ time fields +timezone, and builder validation enforces end-after-start plus positive whole-number signup limits. - Notes: Create, organize, and share notes with your team (Free)
- Board Meetings: Governance workflow for meeting records, agenda, attendance/quorum, motions, minutes approval, transcript context, and template presentations (Plus+ recommended for linked meeting workflows)
- Access Control: Hub accessible to all positions (including
custombase). Individual tools paywalled perTOOL_MINIMUM_TIER. - Real-time: Uses Supabase Realtime for live message updates
- i18n: All strings use
t('workspace.*')keys (Mar 2026)
Related Docs
- 01-MESSENGER.md
- 02-VIDEO-CONFERENCING.md
- 03-PUBLIC-SCHEDULING.md
- 04-GROUP-SCHEDULING-DOODLE.md
- 05-NOTES.md
- BOARD-MEETINGS.md
- DEVELOPER-PLAYBOOK.md
- CORE-ARCHITECTURE-RISK-MAP.md
Data scoping (user vs organization)
Not every tool is purely user-level. The hub is “personal workspace” UX, but some features still filter or attribute data by the header entity (selectedEntity).
| Tool | Primary scope | Notes |
|------|----------------|-------|
| **Messenger** | Conversation / user | Threads are between users; eligibility rules are org-tree–aware. |
| **My Files** | **User + org metadata** | Storage path is `{userId}/…` (user-scoped bucket). **Table RLS** (post JWT migration): inserts require `organization_id` to match `jwt_org_ids()` for fund users, or `jwt_is_parent_org_admin()` for parent org admins. The UI resolves the workspace header entity → `getActualOrgId(selectedEntity)` and passes it on upload/folder create. || **Contacts** | **User** | `contacts` RLS: `user_id = auth.uid()`. `organization_id` nullable; no list filter by entity. |
| **Notes** | **User + shared** | Owner notes/folders are keyed by creator `userId`; shared notes are included via `workspace_note_shares`. Root view shows owner root notes plus all shared notes (including shared notes filed in owner-private folders). Folder views show owner notes in that folder only. Share picker resolves org context via `selectedEntity` → `getOrgId()` / `getActualOrgId()` / `getParentOrgId()`. |
| **Board Meetings** | **Organization** (via entity) | `board_meetings.organization_id` is required. UI resolves org scope from selected workspace entity (`getActualOrgId`). Optional transcript context links to `meetings.id`. |
| **My Calendar** | **Mixed** | Default list uses `getOrgId(selectedEntity)` → `organization_id`. **Team** view (fund/org selected): loads `organization_users` for that org, then all `workspace_events` with that `organization_id` and `created_by` in that member set (not limited to `is_team_visible`). Requires RLS policy `workspace_events_select_org_fund_members`. Parent / no-org header falls back to legacy `is_team_visible` team filter. |
| **Video Conferencing** | **Organization** (via entity) | `fetchMeetings(selectedEntity)` filters `meetings.organization_id` when org resolved; admin view can broaden. |
If the product goal is “everything user-level,” Calendar and Video are the main gaps today.
Architecture
Frontend Structure
src/features/workspace/
├── index.ts # Feature exports
├── components/
│ ├── WorkspacePage.tsx # Main hub page with HubGrid
│ ├── Calendar/
│ │ ├── WorkspaceCalendarManager.tsx
│ │ ├── WorkspaceEventBuilder.tsx
│ │ ├── WorkspaceEventDetail.tsx
│ │ ├── PublicSchedulingSettings.tsx
│ │ ├── PublicSchedulingPage.tsx
│ │ └── PublicCalendarEventPage.tsx
│ ├── Messenger.tsx # Messenger tool container
│ ├── ConversationList.tsx # Sidebar list of conversations
│ ├── MessageThread.tsx # Active conversation view
│ ├── MessageInput.tsx # Message composer with attachments
│ ├── MessageBubble.tsx # Individual message display
│ ├── NewConversationSheet.tsx # Start new conversation sheet
│ └── MessengerDropdown.tsx # Header dropdown for quick messaging
├── hooks/
│ ├── useConversations.ts # Fetch/manage conversations
│ ├── useMessages.ts # Fetch/send messages
│ ├── useRealtimeMessages.ts # Supabase realtime subscription
│ ├── useMessagingPermissions.ts # Check eligible recipients
│ ├── useUnreadMessageCount.ts # Unread badge count (realtime)
│ └── useMessageReactions.ts # Emoji reactions (realtime)
├── utils/
│ └── resolveUserName.ts # Shared name resolver (email fallback)
└── types/
└── messaging.ts # TypeScript typesPublic Scheduling (Calendly-style)
- Staff settings UI:
src/features/workspace/components/Calendar/PublicSchedulingSettings.tsx - Public route:
/schedule/:orgIdPrefix/:orgSlug/:userSlugwhere the first segment is the canonicalpublic_org_keyfor newly emitted links and a legacy UUID prefix for older links. - Public event signup route:
/calendar/:slug(workspace event signup + confirmation flow). - Security note: frontend calendar integration reads only non-secret metadata (connection/sync state). OAuth tokens remain server-side.
Group scheduling (Doodle-style)
- Phase 1: Toolbar link in
WorkspaceCalendarManageropens Doodle in a new tab; see 04-GROUP-SCHEDULING-DOODLE.md. - Phase 2 (planned): Native polls — schema and edge functions described in the same doc.
- Public page component:
src/features/workspace/components/Calendar/PublicSchedulingPage.tsx - Edge functions:
get-public-availability(load public page config + availability)book-scheduling-slot(validate + create booking)- DB module:
src/lib/db/workspace-calendar.ts(fetchPublicCalendarSettings,upsertPublicCalendarSettings)
Database Schema
Four new tables were created:
1. `conversations` - Direct message threads between two users 2. `messages` - Individual messages within conversations 3. `message_attachments` - File attachment metadata 4. `conversation_read_status` - Tracks unread counts per user
RLS Policies
- Users can only see conversations they participate in
- Directors (parent_org admins) can see all conversations within their org scope
- Users can only send messages in conversations they're part of
- Users can only soft-delete their own messages
Paywall Logic
The "My Workspace" sidebar item is visible to all users regardless of tier. Individual tools use TOOL_MINIMUM_TIER / FREE_TIER_PAYWALLED_TOOLS (e.g. Messenger, Video, My Files are Plus+; Contacts, Calendar, Notes are not paywalled the same way—see src/lib/permissions.ts).
Implementation:
my-workspaceis NOT inFREE_TIER_PAYWALLED_HUBS- Several workspace tools ARE in
FREE_TIER_PAYWALLED_TOOLS(not only Messenger) - Free users see the hub but get a paywall modal when opening a paywalled tool
Role-Based Messaging Rules
Fund Users (fund_user role)
Can only message: 1. Users in their parent organization 2. Other users within their same fund
Parent Org Users (parent_org role)
Can message anyone within their organizational scope (all funds under their parent org).
Key Components
WorkspacePage
Main hub page using the standard HubGrid pattern with PageHeader. Shows available tools as tiles with paywall badges for free users.
Messenger
Container component managing:
- Conversation list sidebar
- Message thread view
- New conversation creation
- Mobile responsive layout (stacked view on mobile)
NewConversationSheet
Sheet component for starting new conversations:
- Fetches eligible recipients via
get_eligible_message_recipients()RPC - Searchable list with user avatars and org info
- Creates conversation on selection
MessageBubble
Individual message display with:
- Sender avatar and name (resolved via
resolveUserNamewith email fallback) - Message content with attachments
- Emoji reactions (click bubble to react)
- Timestamp
Database Migrations
20260202_messenger_tables.sql
Creates the four messaging tables with:
- Proper foreign key constraints
- Indexes for performance
- RLS policies for security
- Triggers for
updated_atand unread count management
20260202_messenger_functions.sql
Helper functions:
validate_messaging_permission()- Validates if sender can message recipientget_eligible_message_recipients()- Returns list of users a user can messageget_conversation_participants()- Returns both participants of a conversation
20260202_message_notifications.sql
Notification trigger:
- Creates in-app notifications when new messages are sent
- Notifies the recipient (not the sender)
- Links to the conversation in My Workspace
Notifications
New message notifications use the existing notification system:
- Type:
new_message - Title: "New message from {sender_name}"
- Message: Preview of message content (truncated to 100 chars)
- Link:
/my-workspace?conversation={conversation_id}
Attachments
Supported File Types
- Images: jpg, png, gif, webp
- Documents: pdf, doc, docx, xls, xlsx
- Text: txt, csv
Limits
- Max file size: 50MB
- Max attachments per message: 5
Storage
Files are stored in the message-attachments Supabase Storage bucket with path structure:
{user_id}/{conversation_id}/{timestamp}_{random}_{filename}Mobile Responsiveness
- Desktop (>768px): Side-by-side layout with conversation list and thread
- Mobile (<768px): Stacked layout with navigation between list and thread views
- Back button appears on mobile when viewing a conversation
Error Handling
- Error states displayed with retry buttons
- Graceful degradation if attachments fail to load
- Toast notifications for send/delete failures
Future Enhancements
Potential additions for future releases:
- Typing indicators
- Voice/video calls
- Read receipts
Files Modified
New Files
src/features/workspace/- Entire feature folderbackend/migrations/20260202_messenger_*.sql- Database migrations
Modified Files
src/lib/permissions.ts- Addedmy-workspaceto HubId,messengerto paywalled toolssrc/store/types.ts- Addedmy-workspaceto PageView typesrc/components/shared/AppSidebar.tsx- Added My Workspace sidebar itemsrc/App.tsx- Added routing for my-workspace pagesrc/i18n/locales/en/common.json- Added translation keysrc/lib/imageUtils.ts- Added attachment upload utilities
Synced from IFMmvp-Frontend documentation: workspace/00-WORKSPACE-HUB.md
Ready to Get Started?
See how Alignmint can simplify your nonprofit's operations. Schedule a free demo with our team and we'll walk you through everything.
Questions? Email us at steven@getalignmint.org