Files
cannamanage/docs/sprint-7/cannamanage-sprint7-analysis.md
Patrick Plate 706a6e257b feat(sprint7): Phase 1 — notifications enhancement + push infrastructure
Phase 1 (Notification Enhancement):
- Extended NotificationType enum (ADMIN_MESSAGE, INFO_BOARD_POST, FORUM_REPLY, FORUM_MENTION)
- Extended StaffPermission enum (SEND_NOTIFICATIONS, MANAGE_INFO_BOARD, MODERATE_FORUM)
- Extended AuditEventType with Sprint 7 events
- Flyway V11: notification_sends + notification_send_recipients tables
- NotificationSend + NotificationSendRecipient entities
- NotificationSendRepository + NotificationSendRecipientRepository
- Extended NotificationService with sendBroadcast() and sendToSelected()
- NotificationComposeController (POST /compose, GET /sends)
- ComposeNotificationRequest DTO

Phase 1B (Push Infrastructure):
- Flyway V12: device_tokens + notification_preferences tables
- DeviceToken entity + DevicePlatform enum
- NotificationPreference entity + NotificationChannel enum
- DeviceTokenRepository + NotificationPreferenceRepository
- DeviceRegistrationService (register/unregister/list devices, max 10 per user)
- NotificationPreferenceService (get/create defaults, update, IN_APP always on)
- NotificationDispatchService (multi-channel fan-out: WebSocket, Web Push, FCM, Email)
- WebPushSender (VAPID-based, simplified for MVP)
- FcmPushSender (graceful degradation if not configured)
- PushPayload DTO
- DeviceRegistrationController (POST/GET/DELETE /devices, GET /vapid-key)
- NotificationPreferenceController (GET/PUT /preferences)
- ConsentType extended (NOTIFICATION_PUSH, NOTIFICATION_EMAIL)
- TargetType enum (ALL, SELECTED)

Frontend:
- Updated sw.js with push event handler + notification click handler
- push-subscription.ts (subscribeToPush, unsubscribe, permission helpers)
- notification-compose.ts service (compose, sends, devices, preferences APIs)
- i18n keys (de.json + en.json) for compose, preferences, push, devices

Configuration:
- application-docker.properties: VAPID + FCM push config properties
- MemberRepository: added findAllActiveUserIds() for broadcast
2026-06-13 19:25:19 +02:00

39 KiB

Sprint 7 Feature Analysis — Communication & Community

Date: 2026-06-13 Author: Patrick Plate / Lumen (Architect) Status: Draft v1 Sprint Goal: Transform CannaManage from a compliance tool into a community platform — the communication layer that keeps members engaged and clubs organized.


Executive Summary

Sprint 7 introduces four communication features that turn CannaManage from "backend compliance software" into a living club platform. The recommended Sprint 7 scope is:

  1. Club Info Board (Schwarzes Brett) — ship it. Core feature, medium effort, high engagement value.
  2. Club-Internal Forum — ship it (MVP). Threaded discussions within a club. High member engagement, competitive differentiator.
  3. Club-to-Member Notifications (admin-composed) — ship it. Builds on existing Sprint 6 infrastructure. Low effort, high value.
  4. Cross-Club Community Forum — defer to Sprint 8+. Legal complexity (KCanG), moderation overhead, and "nice to have" status make it wrong for this sprint.

Strategic rationale: No competitor (420cloud, Hanf-App, Cannanas) offers in-app community features. Clubs currently use Telegram/Signal/WhatsApp groups, which are unmoderated, unarchived, and disconnected from the platform. Owning the communication layer creates massive switching costs — once a club's discussions live in CannaManage, they can't leave without losing history.


1. Club Info Board (Schwarzes Brett)

1.1 Problem Statement

Club admins need a one-to-many broadcast channel: announcements, rule changes, event notices, operational updates ("We're closed next Thursday"), new strain arrivals. Today this happens in Telegram groups where messages get buried, new members miss old announcements, and there's no archive.

The Info Board is not a conversation — it's a pinboard. Staff posts, members read. Think: physical Schwarzes Brett in the club room, digitized.

1.2 How It Differs from Notifications

Aspect Notifications Info Board
Trigger System-generated events (quota warning, batch recalled) Human-authored by admin/staff
Persistence Transient — read and dismiss Permanent — archived, searchable
Visibility Individual user inbox All club members see all posts
Rich content Short text + link Rich text, images, attachments
Categories NotificationType enum Admin-defined categories
Interaction Mark as read Pin, archive, comment (optional)

1.3 User Stories

# As a... I want to... So that... Priority
IB-01 Club Admin Post an announcement with title, body, and category All members see it on their dashboard P0
IB-02 Club Admin Pin an important post to the top Critical info (rules, hours) stays visible P0
IB-03 Club Admin Attach images or PDFs to a post I can share event flyers or updated rules docs P1
IB-04 Club Admin Archive old posts (not delete) The board stays clean but history is preserved P1
IB-05 Club Admin Assign categories (Events, Rules, General, Strain News) Members can filter what interests them P1
IB-06 Staff (with permission) Post announcements The admin doesn't have to do everything P0
IB-07 Member See announcements on my portal dashboard I don't miss important club news P0
IB-08 Member Filter posts by category I only see what's relevant to me P2
IB-09 Member Get notified when a new post appears I'm alerted even if I don't check the board P1

1.4 Data Model

-- V11: Info Board
CREATE TABLE info_board_categories (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(100) NOT NULL,
    color VARCHAR(7),             -- hex color for UI badge
    sort_order INTEGER NOT NULL DEFAULT 0,
    tenant_id UUID NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE TABLE info_board_posts (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    title VARCHAR(255) NOT NULL,
    body TEXT NOT NULL,            -- markdown or sanitized HTML
    category_id UUID REFERENCES info_board_categories(id),
    author_id UUID NOT NULL,      -- staff or admin user
    pinned BOOLEAN NOT NULL DEFAULT false,
    archived BOOLEAN NOT NULL DEFAULT false,
    published_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    tenant_id UUID NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE TABLE info_board_attachments (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    post_id UUID NOT NULL REFERENCES info_board_posts(id) ON DELETE CASCADE,
    filename VARCHAR(255) NOT NULL,
    content_type VARCHAR(100) NOT NULL,
    size_bytes BIGINT NOT NULL,
    storage_path VARCHAR(500) NOT NULL,
    tenant_id UUID NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_info_board_posts_tenant ON info_board_posts(tenant_id, archived, pinned DESC, published_at DESC);
CREATE INDEX idx_info_board_posts_category ON info_board_posts(category_id);

Key design decisions:

  • Markdown body (rendered on frontend) — simple, secure, no XSS risk from raw HTML
  • pinned as boolean — pinned posts sort first, then by published_at DESC
  • Soft-archive (not delete) — compliance friendliness, audit trail integrity
  • Attachments stored on filesystem (or S3-compatible) — not in DB

1.5 UI Mockup Description

Admin/Staff view (Dashboard → Info Board):

  • Top: "New Post" button (opens rich text editor)
  • Category filter tabs (All | Events | Rules | General | Strain News)
  • Post list: card layout with title, excerpt, author, date, pinned badge
  • Each card: actions dropdown (Edit, Pin/Unpin, Archive)
  • Attachment upload: drag-and-drop zone in the editor

Portal/Member view (Portal Dashboard → Announcements section):

  • Latest 3-5 posts shown as cards on the portal dashboard
  • "View All" link → dedicated announcements page
  • Category color badges
  • Pinned posts have a 📌 indicator and always show first
  • Unread indicator (new posts since last visit)

1.6 Integration Points

Integration How
Notifications (existing) New post → auto-generate INFO_BOARD_POST notification for all club members
WebSocket (existing) Push new-post event in real-time to connected members
Audit Log (existing) Log post creation, edits, archives as INFO_BOARD_CREATED / INFO_BOARD_EDITED / INFO_BOARD_ARCHIVED
StaffPermission New permission: MANAGE_INFO_BOARD — controls who can post/edit/archive

1.7 Plan Tier Mapping

Tier Info Board Access
Starter Basic (3 categories max, no attachments)
Pro Full (unlimited categories, attachments up to 10 MB)
Enterprise Full + scheduled posts, auto-archive after N days

2. Club-Internal Forum (Vereinsinterne Diskussion)

2.1 Problem Statement

Members want to talk to each other — not just passively receive announcements. Today they use Telegram/WhatsApp groups that are:

  • Unmoderated (spam, off-topic, conflicts)
  • Ephemeral (messages get buried, no searchable archive)
  • Disconnected from the club platform (no link to member profiles, no awareness of club context)
  • A privacy leak (phone numbers exposed to all members)

A club-internal forum gives members a place to discuss within the platform — moderated, archived, searchable, and integrated with member identity.

2.2 How It Differs from Info Board

Aspect Info Board Forum
Direction One-to-many (staff → members) Many-to-many (members ↔ members)
Who posts Admin/Staff only All members
Structure Flat list of posts Threaded: Topics → Replies
Moderation N/A (staff controls everything) Staff can moderate, lock, delete
Purpose Official communication Community discussion

2.3 User Stories

# As a... I want to... So that... Priority
FO-01 Member Create a new discussion topic I can ask questions or start conversations P0
FO-02 Member Reply to an existing topic I can participate in discussions P0
FO-03 Member Browse topics by category I find relevant discussions P0
FO-04 Member See who posted (display name + avatar) I know who I'm talking to P0
FO-05 Member Edit my own posts (within 30 min) I can fix typos P1
FO-06 Member Report inappropriate posts I can flag content for moderators P1
FO-07 Staff/Admin Create and manage forum categories Discussions are organized P0
FO-08 Staff/Admin Delete posts / lock topics I can moderate inappropriate content P0
FO-09 Staff/Admin Pin important topics Key discussions stay visible P1
FO-10 Staff/Admin See reported posts in a moderation queue I can act on reports efficiently P1
FO-11 Member Get notified when someone replies to my topic I don't miss responses P1
FO-12 Member Upload images in posts I can share photos (grow results, events) P2
FO-13 Member React to posts (thumbs up, leaf emoji) I can show appreciation without cluttering P2

2.4 Data Model

-- V12: Club-Internal Forum
CREATE TABLE forum_categories (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(100) NOT NULL,
    description VARCHAR(500),
    icon VARCHAR(50),             -- emoji or icon name
    sort_order INTEGER NOT NULL DEFAULT 0,
    tenant_id UUID NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE TABLE forum_topics (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    title VARCHAR(255) NOT NULL,
    body TEXT NOT NULL,            -- first post content (markdown)
    category_id UUID NOT NULL REFERENCES forum_categories(id),
    author_id UUID NOT NULL,      -- member or staff user
    pinned BOOLEAN NOT NULL DEFAULT false,
    locked BOOLEAN NOT NULL DEFAULT false,
    reply_count INTEGER NOT NULL DEFAULT 0,
    last_reply_at TIMESTAMP WITH TIME ZONE,
    last_reply_by UUID,
    tenant_id UUID NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE TABLE forum_replies (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    topic_id UUID NOT NULL REFERENCES forum_topics(id) ON DELETE CASCADE,
    body TEXT NOT NULL,            -- markdown
    author_id UUID NOT NULL,
    edited_at TIMESTAMP WITH TIME ZONE,
    tenant_id UUID NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE TABLE forum_reports (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    reporter_id UUID NOT NULL,
    target_type VARCHAR(10) NOT NULL,  -- 'TOPIC' or 'REPLY'
    target_id UUID NOT NULL,
    reason VARCHAR(500) NOT NULL,
    resolved BOOLEAN NOT NULL DEFAULT false,
    resolved_by UUID,
    resolved_at TIMESTAMP WITH TIME ZONE,
    tenant_id UUID NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);

CREATE TABLE forum_reactions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL,
    target_type VARCHAR(10) NOT NULL,  -- 'TOPIC' or 'REPLY'
    target_id UUID NOT NULL,
    reaction VARCHAR(20) NOT NULL,    -- 'thumbsup', 'leaf', 'fire', 'heart'
    tenant_id UUID NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    UNIQUE(user_id, target_type, target_id, reaction)
);

CREATE INDEX idx_forum_topics_tenant ON forum_topics(tenant_id, category_id, pinned DESC, last_reply_at DESC);
CREATE INDEX idx_forum_replies_topic ON forum_replies(topic_id, created_at);
CREATE INDEX idx_forum_reports_unresolved ON forum_reports(tenant_id, resolved, created_at);

Key design decisions:

  • Flat replies (not nested/threaded) — simpler UX, easier to follow, works on mobile
  • reply_count + last_reply_at denormalized on topics — avoids expensive JOINs for listing
  • Edit window: 30 minutes (set in application logic, not DB)
  • Reactions: limited set (4-5 emojis) — not free-form to keep it simple
  • Reports go to a moderation queue — staff sees flagged content

2.5 Moderation Features

Feature How It Works
Delete post/reply Staff removes content, replaced with "[Beitrag entfernt]" placeholder
Lock topic No new replies allowed. Existing content preserved.
Pin topic Pinned topics always appear at the top of category view
Report queue Members flag → staff sees queue → resolve (delete, warn, or dismiss)
Auto-lock inactive Topics with no replies for 90 days auto-lock (configurable)
Word filter Optional blocklist (admin-configured) — posts with blocked words held for review

New StaffPermission: MODERATE_FORUM — controls access to moderation queue and lock/delete actions.

2.6 UI Mockup Description

Forum main page (Dashboard → Forum):

  • Category cards with name, description, topic count, last activity
  • "New Topic" button (per category or global)
  • Search bar (full-text search across topics and replies)

Category view:

  • Topic list: title, author, reply count, last reply date
  • Pinned topics at top with badge
  • Locked topics with lock icon
  • Pagination (20 topics per page)

Topic view:

  • Original post at top
  • Replies below in chronological order
  • Reply editor at bottom (markdown with preview)
  • Reaction buttons on each post
  • "Report" link on each post (subtle, doesn't clutter)
  • Lock/Delete/Pin controls for staff (contextual)

Portal/Member view:

  • Same forum, just within the portal layout
  • Members see their own posts highlighted
  • "My Topics" and "Subscribed" quick filters

2.7 Plan Tier Mapping

Tier Forum Access
Starter Not included (upgrade incentive)
Pro Full forum (5 categories max)
Enterprise Full forum (unlimited categories, custom word filter, advanced moderation)

3. Cross-Club Community Forum

3.1 Problem Statement

Members from different clubs may want to exchange knowledge — growing tips, legal questions, strain reviews, event coordination. Currently there's no platform-level community; people use Reddit, Telegram, or CannaConnection forums.

A cross-club forum would make CannaManage a "social network for CSC members" — a powerful retention mechanism. But it also introduces significant complexity: moderation at scale, privacy concerns, and legal implications under KCanG.

3.2 User Stories

# As a... I want to... So that... Priority
CC-01 Member Browse community topics from all clubs I can learn from other clubs' experiences P1
CC-02 Member Post in the community forum I can share knowledge with the wider community P1
CC-03 Member Choose to appear as "Member of [ClubName]" or anonymous I control my privacy P0
CC-04 Platform Admin Moderate cross-club content The community stays safe and legal P0
CC-05 Platform Admin Define community-wide categories Content is organized P0
CC-06 Club Admin Opt their club in/out of community features They control member exposure P1

3.3 Data Model (Multi-Tenant Considerations)

The cross-club forum breaks the fundamental tenant_id isolation pattern. Every other entity in CannaManage is scoped to a single club. A cross-club entity needs either:

Option A: Separate schema (no tenant_id)

-- community_topics, community_replies — NOT extending AbstractTenantEntity
-- Use a separate 'platform_user_id' that maps to the user across clubs

Option B: Platform-level tenant (tenant_id = NULL or platform UUID)

-- A special "platform" tenant that all users can access
-- More complex query logic: WHERE tenant_id = :current OR tenant_id = :platform

Recommendation: Option A — separate schema. The cross-club forum is architecturally a different bounded context. Mixing it with tenant-scoped entities creates query complexity and potential data leakage bugs.

Concern Analysis Risk Level
KCanG §4 — Advertising prohibition CSCs may not advertise cannabis or their club publicly. A cross-club forum where clubs share their strains could be interpreted as advertising. 🟡 Medium
KCanG §18 — Data handling Member data must be handled with care. Cross-club exposure of member names (even display names) to non-club-members may violate the principle of data minimization. 🟡 Medium
DSGVO Art. 5(1)(c) — Data minimization Exposing member identity across clubs goes beyond what's necessary for club management. Must offer genuine anonymity option. 🔴 High
KCanG §5 — Membership restriction Members can only belong to one CSC. If the forum reveals multi-club participation, it could expose legal violations. 🟡 Medium
Platform liability If the platform hosts inter-club communication, it becomes a publisher/moderator of cannabis-related content. Illegal content (sales, purchases) is a risk. 🔴 High
Age verification KCanG requires age verification for membership. A community forum accessible to "all members" must ensure all participants are verified. 🟢 Low (all members already verified)

Legal recommendation: If built, the cross-club forum MUST:

  1. Default to anonymous posting (no club name, no real name)
  2. Prohibit any form of transaction/trade discussion
  3. Include clear terms of use that forbid advertising
  4. Have active platform-level moderation
  5. Allow clubs to opt-out entirely
  6. Allow individual members to opt-out

3.5 Moderation at Platform Level

Challenge Solution
Scale Platform admin team or community moderators (elevated non-admin users)
Illegal content Automated keyword filtering + user reports + manual review
Cross-club disputes Platform terms of service, not individual club rules
Reporting to authorities If illegal activity is detected, platform has Mitwirkungspflicht
Content liability Clear Terms of Service, notice-and-takedown procedure

3.6 Recommendation: Defer to Sprint 8+

Reasons to defer:

  1. Legal complexity — needs actual legal review (not just developer analysis)
  2. Architectural break — violates the clean tenant isolation model; needs careful design
  3. Moderation overhead — requires platform-level moderation tooling that doesn't exist yet
  4. Low priority — club-internal communication is far more valuable than inter-club
  5. Competitive non-urgency — no competitor has this either; no market pressure
  6. MVP path — clubs can still use Telegram for inter-club chat; CannaManage solves the intra-club problem first

When to revisit: After 50+ clubs are on the platform and actively request it. Validate demand before building.

3.7 Plan Tier Mapping (if eventually built)

Tier Community Forum
Starter Not included
Pro Read-only access
Enterprise Full access (post + moderate)

4. Club Notifications to Members (Benachrichtigungen)

4.1 Existing Infrastructure (What We Already Have)

Sprint 6 delivered a solid notification foundation:

Component Status Details
notifications table Built UUID PK, user_id, type, title, message, link, read flag, tenant_id
Notification entity Built JPA entity extending AbstractTenantEntity
NotificationType enum Built 4 system types: QUOTA_WARNING, BATCH_RECALLED, DISTRIBUTION_RECORDED, SUBSCRIPTION_EXPIRING
REST API (/notifications) Built GET list, PUT mark-read, PUT mark-all-read
Frontend service Built getNotifications(), markNotificationAsRead(), markAllNotificationsAsRead()
WebSocket (SockJS/STOMP) Built Real-time push to connected clients (Nginx configured for /ws/ upgrade)
PWA + Service Worker Built Manifest, offline page, install prompt (Sprint 6 Phase 6)
Bell icon in nav Built Unread count badge in dashboard header

What works today: System-generated notifications (triggered by backend events) get stored in the DB, pushed via WebSocket to the frontend, and shown in the bell dropdown. Members can mark them as read.

4.2 Gap Analysis (What's Missing)

Gap Description Effort
Admin compose UI No interface for admins to write and send custom notifications Medium
Targeting Current notifications are individual (user_id). No way to send to "all members" or "members in group X" Medium
Custom notification types Only 4 system types. Need ADMIN_MESSAGE, INFO_BOARD_POST, FORUM_REPLY Low
Email delivery channel Notifications are in-app only. No email fallback for offline users Medium
Push notifications (Web Push API) PWA exists but Web Push subscription/delivery not implemented Medium
Scheduling Can't schedule a notification for future delivery Low
Templates No template system for recurring notifications Low
Read receipts Admin can't see who read the notification Low
Member groups/segments No concept of member groups for targeted sending Medium

4.3 User Stories

# As a... I want to... So that... Priority
NT-01 Club Admin Compose a custom notification with title + message I can reach members directly P0
NT-02 Club Admin Send to all members at once I don't have to select each one individually P0
NT-03 Club Admin Send to specific members (multi-select) I can target a subset P1
NT-04 Club Admin Preview before sending I catch mistakes before broadcasting P0
NT-05 Club Admin See delivery stats (sent/read counts) I know if members are getting the message P1
NT-06 Member Receive notifications in-app (real-time) I see messages immediately when online P0
NT-07 Member Receive email for important notifications (opt-in) I don't miss things when offline P1
NT-08 Member Control which notification types I receive I'm not overwhelmed P2
NT-09 Club Admin Schedule a notification for later I can prepare communications in advance P2

4.4 Admin UI for Composing Notifications

Page: Dashboard → Notifications → Compose

┌─────────────────────────────────────────────────┐
│  📣 Neue Benachrichtigung                        │
├─────────────────────────────────────────────────┤
│                                                 │
│  Empfänger: [● Alle Mitglieder ▼]              │
│             ○ Ausgewählte Mitglieder            │
│             [Search + multi-select chips]        │
│                                                 │
│  Titel:    [____________________________]       │
│                                                 │
│  Nachricht:                                     │
│  ┌─────────────────────────────────────────┐   │
│  │ (Markdown editor with preview toggle)    │   │
│  │                                          │   │
│  └─────────────────────────────────────────┘   │
│                                                 │
│  Link (optional): [________________________]    │
│                                                 │
│  □ Auch per E-Mail senden                       │
│                                                 │
│  [Vorschau]              [Senden]               │
│                                                 │
└─────────────────────────────────────────────────┘

Notification History page:

  • Table of sent notifications with: title, recipients (count), sent date, read rate
  • Click to see per-recipient read status
  • Resend option for unread recipients

4.5 Delivery Channels

Channel Implementation Priority
In-app (WebSocket) Already works. Extend to handle ADMIN_MESSAGE type. P0 (exists)
In-app (polling fallback) Already works via REST GET /notifications. P0 (exists)
Email Use existing EmailService. New template: notification-email.txt. Opt-in per member. P1
Web Push Register subscription via Push API. Backend stores endpoint + keys. Send via web-push library. P2 (Sprint 8)

4.6 Targeting (All, Groups, Individuals)

Phase 1 (Sprint 7):

  • Send to ALL members (broadcast)
  • Send to selected individuals (multi-select picker)

Phase 2 (Sprint 8+):

  • Member groups/segments (e.g., "Board Members", "Active Growers", "New Members < 30 days")
  • Tag-based targeting
  • Dynamic segments (members who haven't visited in 30 days)

4.7 Data Model Changes

-- Extend NotificationType enum (code change only, no migration needed)
-- Add: ADMIN_MESSAGE, INFO_BOARD_POST, FORUM_REPLY, FORUM_MENTION

-- V13: Notification send log (for admin-composed notifications)
CREATE TABLE notification_sends (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    title VARCHAR(255) NOT NULL,
    message TEXT NOT NULL,
    link VARCHAR(500),
    author_id UUID NOT NULL,
    target_type VARCHAR(20) NOT NULL,  -- 'ALL', 'SELECTED'
    target_count INTEGER NOT NULL,
    read_count INTEGER NOT NULL DEFAULT 0,
    sent_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    tenant_id UUID NOT NULL
);

CREATE TABLE notification_send_recipients (
    send_id UUID NOT NULL REFERENCES notification_sends(id) ON DELETE CASCADE,
    user_id UUID NOT NULL,
    notification_id UUID REFERENCES notifications(id),  -- links to the actual notification created
    PRIMARY KEY (send_id, user_id)
);

CREATE INDEX idx_notification_sends_tenant ON notification_sends(tenant_id, sent_at DESC);

5. Prioritization & Sprint Plan

5.1 Feature Priority Matrix

Feature User Value Competitive Edge Build Effort Risk Sprint 7?
Club Notifications (admin compose) 🟢 High 🟢 Medium 🟢 Low (builds on existing) 🟢 Low Yes
Club Info Board 🟢 High 🟢 High (no competitor has it) 🟡 Medium 🟢 Low Yes
Club-Internal Forum 🟢 High 🟢 High (no competitor has it) 🟡 Medium-High 🟡 Medium (moderation) Yes (MVP)
Cross-Club Forum 🟡 Medium 🟡 Medium 🔴 High 🔴 High (legal, arch) Defer
Phase 1: Admin Notifications (builds on existing infra)
Phase 2: Info Board (Schwarzes Brett)
Phase 3: Forum MVP (categories, topics, replies, basic moderation)
Phase 4: Integration (notifications ↔ info board ↔ forum)
Phase 5: Polish & testing

Phase 1 — Admin Notifications

Step Description
1.1 Extend NotificationType enum: ADMIN_MESSAGE, INFO_BOARD_POST, FORUM_REPLY
1.2 Add notification_sends table (Flyway V13)
1.3 Backend: NotificationComposeService — create notification for multiple recipients
1.4 Backend: POST /api/v1/notifications/compose endpoint
1.5 Frontend: Compose notification page (admin area)
1.6 Frontend: Notification history page with read stats
1.7 Email delivery: notification email template + opt-in flag on member
1.8 New StaffPermission: SEND_NOTIFICATIONS

Phase 2 — Info Board

Step Description
2.1 info_board_categories + info_board_posts + info_board_attachments tables (Flyway V14)
2.2 Backend: InfoBoardService — CRUD for categories and posts
2.3 Backend: REST endpoints POST/GET/PUT /api/v1/info-board/posts, GET /api/v1/info-board/categories
2.4 Backend: File upload endpoint for attachments
2.5 Frontend (admin): Info Board management page (create, edit, pin, archive)
2.6 Frontend (portal): Announcements section on member dashboard + dedicated page
2.7 Integration: New post → auto-notify all members (uses Phase 1 infra)
2.8 New StaffPermission: MANAGE_INFO_BOARD

Phase 3 — Forum MVP

Step Description
3.1 Forum tables (Flyway V15): categories, topics, replies, reports, reactions
3.2 Backend: ForumService — topics CRUD, replies CRUD, moderation actions
3.3 Backend: REST endpoints for forum (topics, replies, categories, reports)
3.4 Frontend: Forum page (category list → topic list → topic detail with replies)
3.5 Frontend: New topic / reply editors (markdown)
3.6 Frontend: Moderation panel (report queue, lock/delete actions)
3.7 Integration: Reply notification → auto-notify topic author
3.8 New StaffPermission: MODERATE_FORUM

Phase 4 — Integration & Polish

Step Description
4.1 WebSocket events for new info board posts and forum replies
4.2 Audit log events for info board and forum actions
4.3 Portal navigation update (add Forum, Announcements)
4.4 Dashboard widget: "Latest Announcements" + "Recent Forum Activity"
4.5 Email notifications for forum replies (opt-in)

Phase 5 — Testing

Step Description
5.1 Unit tests for all new services
5.2 Integration tests for forum + info board + notifications
5.3 E2E tests (Playwright): post announcement, create topic, reply
5.4 Tenant isolation verification (no cross-club data leaks)
5.5 Permission checks (unauthorized staff can't post/moderate)

5.3 Deferred to Sprint 8+

Feature Reason When
Cross-Club Community Forum Legal review needed, architecture break Sprint 9+ (if validated)
Web Push Notifications PWA push subscription, VAPID keys Sprint 8
Member groups / segments Low urgency, "all members" is sufficient for MVP Sprint 8
Scheduled notifications Nice-to-have, not blocking Sprint 8
Forum image uploads Moderation complexity, storage cost Sprint 8
Forum search (full-text) PostgreSQL FTS setup, medium effort Sprint 8
Notification preferences (per-type opt-in/out) UX complexity Sprint 8
Rich text editor (WYSIWYG vs markdown) Markdown is sufficient for MVP Sprint 9

5.4 Dependencies Between Features

graph TD
    A[Phase 1: Admin Notifications] --> B[Phase 2: Info Board]
    A --> C[Phase 3: Forum MVP]
    B --> D[Phase 4: Integration]
    C --> D
    D --> E[Phase 5: Testing]
    
    subgraph Existing Infrastructure
        N[Notification entity + table]
        W[WebSocket STOMP]
        P[StaffPermission system]
        AU[AuditService]
    end
    
    N --> A
    W --> A
    P --> A
    P --> B
    P --> C
    AU --> D

Critical path: Phase 1 must come first because Phases 2 and 3 depend on it for their notification integration.


6. Technical Architecture

6.1 New Entities & Migrations

Migration Tables Entity Classes
V11 info_board_categories, info_board_posts, info_board_attachments InfoBoardCategory, InfoBoardPost, InfoBoardAttachment
V12 forum_categories, forum_topics, forum_replies, forum_reports, forum_reactions ForumCategory, ForumTopic, ForumReply, ForumReport, ForumReaction
V13 notification_sends, notification_send_recipients NotificationSend, NotificationSendRecipient

All new entities extend AbstractTenantEntity — tenant isolation by default.

6.2 API Endpoints

# Admin Notifications
POST   /api/v1/notifications/compose        — Send notification to targets
GET    /api/v1/notifications/sends           — List sent notifications (admin)
GET    /api/v1/notifications/sends/{id}      — Get send details + per-recipient status

# Info Board
GET    /api/v1/info-board/categories         — List categories
POST   /api/v1/info-board/categories         — Create category (admin)
PUT    /api/v1/info-board/categories/{id}    — Update category (admin)
GET    /api/v1/info-board/posts              — List posts (paginated, filterable)
POST   /api/v1/info-board/posts              — Create post (staff with permission)
PUT    /api/v1/info-board/posts/{id}         — Update post
PUT    /api/v1/info-board/posts/{id}/pin     — Toggle pin
PUT    /api/v1/info-board/posts/{id}/archive — Archive post
POST   /api/v1/info-board/posts/{id}/attachments — Upload attachment
GET    /api/v1/info-board/posts/{id}/attachments/{aid} — Download attachment

# Forum
GET    /api/v1/forum/categories              — List forum categories
POST   /api/v1/forum/categories              — Create category (admin)
GET    /api/v1/forum/topics                  — List topics (paginated, by category)
POST   /api/v1/forum/topics                  — Create topic (any member)
GET    /api/v1/forum/topics/{id}             — Get topic with replies (paginated)
PUT    /api/v1/forum/topics/{id}             — Edit topic (author, within 30 min)
PUT    /api/v1/forum/topics/{id}/pin         — Pin topic (moderator)
PUT    /api/v1/forum/topics/{id}/lock        — Lock topic (moderator)
DELETE /api/v1/forum/topics/{id}             — Delete topic (moderator)
POST   /api/v1/forum/topics/{id}/replies     — Post reply (any member)
PUT    /api/v1/forum/replies/{id}            — Edit reply (author, within 30 min)
DELETE /api/v1/forum/replies/{id}            — Delete reply (moderator)
POST   /api/v1/forum/reports                 — Report a post/reply
GET    /api/v1/forum/reports                 — List reports (moderator)
PUT    /api/v1/forum/reports/{id}/resolve    — Resolve report (moderator)
POST   /api/v1/forum/reactions               — Add reaction
DELETE /api/v1/forum/reactions/{id}          — Remove reaction

6.3 Frontend Pages/Components

Admin Dashboard additions:

  • /settings/info-board — Info Board management (categories + post editor)
  • /settings/notifications/compose — Compose notification
  • /settings/notifications/history — Sent notifications log
  • /forum — Forum with admin moderation controls

Portal additions:

  • /portal/announcements — All info board posts
  • /portal/forum — Forum access for members
  • Portal dashboard: "Announcements" widget + "Forum Activity" widget

Shared components:

  • MarkdownEditor — textarea with preview toggle (reusable for info board + forum)
  • CategoryBadge — colored badge component
  • ReactionBar — reaction emoji buttons with counts
  • ModerationActions — dropdown with delete/lock/pin (shown to staff)

6.4 WebSocket Integration

Extend the existing STOMP broker with new message types:

/topic/club/{tenantId}/notifications  — existing (extend with new types)
/topic/club/{tenantId}/info-board     — new post published
/topic/club/{tenantId}/forum          — new topic or reply in subscribed topic

Frontend subscription (React hook):

// useForumSubscription(topicId) → real-time new replies
// useInfoBoardSubscription() → real-time new posts  
// useNotificationSubscription() → existing, extended with ADMIN_MESSAGE

6.5 Search & Performance Considerations

Concern Solution
Forum topic listing performance Denormalized reply_count + last_reply_at on topic table. Paginate at 20 per page.
Info board post search PostgreSQL ILIKE on title + body for MVP. Full-text search (tsvector) in Sprint 8 if needed.
Notification fan-out (send to 500 members) Batch INSERT using JdbcTemplate.batchUpdate(). Don't create 500 individual transactions.
WebSocket scaling Single server is fine for MVP (< 1000 concurrent connections). Redis pub/sub for horizontal scaling if needed later.
Attachment storage Local filesystem for MVP (/data/attachments/{tenant_id}/{post_id}/). S3-compatible object storage for production scale.
Forum reaction counting COUNT(*) with GROUP BY on reactions table. Cache in application if >1000 reactions per post (unlikely in Sprint 7).

7. New StaffPermissions Summary

public enum StaffPermission {
    RECORD_DISTRIBUTION,
    VIEW_MEMBER_LIST,
    VIEW_MEMBER_QUOTA,
    ADD_MEMBER,
    VIEW_STOCK,
    RECORD_STOCK_IN,
    VIEW_COMPLIANCE_REPORT,
    MANAGE_GROW_CALENDAR,
    // Sprint 7 additions:
    SEND_NOTIFICATIONS,      // Compose + send admin notifications
    MANAGE_INFO_BOARD,       // Create/edit/pin/archive info board posts
    MODERATE_FORUM           // Delete posts, lock topics, resolve reports
}

8. GDPR/KCanG Compliance Checklist

Requirement How We Address It
DSGVO Art. 5 — Data minimization Forum posts only show display name (never real name or email). No data shared cross-club.
DSGVO Art. 17 — Right to erasure Member deletion cascades to their forum posts (anonymized, not removed: "Ehemaliges Mitglied")
DSGVO Art. 15 — Data export Export includes forum posts and info board interactions in data package
KCanG §4 — No advertising Forum rules explicitly prohibit strain advertising. Moderation enforces this.
KCanG §18 — Data handling All communication data scoped to tenant_id. No cross-club exposure. Club admin controls who can participate.
Audit compliance Info board posts and moderation actions logged in immutable audit trail

9. Risk Assessment

Risk Probability Impact Mitigation
Moderation burden overwhelms club admins Medium Medium Start with simple report queue. Auto-lock inactive topics. Word filter optional.
Low member engagement with forum Medium Low Info Board is one-way (guaranteed content). Forum is additive. Don't over-invest.
Markdown too technical for non-technical admins Low Medium Provide a toolbar (bold/italic/link buttons) over the textarea. Add preview.
Attachment storage fills disk Low Medium Set max file size (10 MB). Set per-club storage quota (100 MB Starter, 1 GB Pro).
Notification spam (admin sends too often) Low Medium Show "last sent" timestamp. Optional daily digest mode in Sprint 8.
Tenant isolation bug (cross-club data leak) Low 🔴 Critical Integration test specifically for tenant isolation on all new entities. AbstractTenantEntity pattern prevents most issues.

10. Success Metrics

Metric Target (3 months post-launch) How to Measure
Info Board posts created 5+ per club per month Count info_board_posts per tenant per month
Forum topics created 10+ per club per month Count forum_topics per tenant per month
Admin notifications sent 3+ per club per month Count notification_sends per tenant per month
Member forum participation rate >30% of members posted at least once Distinct author_id / total members
Notification read rate >70% within 48 hours read_count / target_count on notification_sends
Moderation queue response time <24 hours Time between report creation and resolution