An introduction to the project is in the frontend README: https://github.com/gennit-project/multiforum-frontend
On the backend (https://github.com/gennit-project/multiforum-backend), an Apollo server fetches data from the database (a graph database, Neo4j). Some resolvers are auto-generated using the Neo4j graphql library, while more complex resolvers are implemented using a combination of the OGM and custom Cypher queries.
The frontend is a Vue application that makes GraphQL queries to the Apollo server.
Multiforum uses a comprehensive role-based permission system that governs what actions users can perform across the platform. The system operates at both server-wide and channel-specific levels.
The permission system uses the following components:
-
Server Roles - Server-wide role definitions for regular users
- Define baseline permissions for all users across the platform
- Examples:
canCreateChannel
,canCreateDiscussion
,canUpvoteComment
-
Channel Roles - Channel-specific role definitions for regular users
- Define permissions for actions within specific channels
- Examples:
canCreateDiscussion
,canCreateComment
,canUpvoteDiscussion
-
Mod Server Roles - Server-wide role definitions for moderators
- Define baseline moderation capabilities across all channels
- Examples:
canHideComment
,canGiveFeedback
,canSuspendUser
-
Mod Channel Roles - Channel-specific role definitions for moderators
- Define moderation capabilities within specific channels
- Examples:
canHideDiscussion
,canGiveFeedback
,canReport
-
Suspended Roles - Define restricted permissions for suspended users/moderators
- Different variants for regular users and moderators
- Typically limit user capabilities while suspended
- Regular Users - Standard platform users
- Channel Owners - Have administrative control over specific channels
- Moderators - Users with moderation capabilities
- Suspended Users - Users with temporarily restricted permissions
The permission system follows a hierarchical flow:
-
Authentication Check
- Verifies that the user is logged in and their JWT is valid
-
Role Determination
- For each action, the system determines which role applies to the user
- The system follows this priority order when determining permissions:
- For regular user actions (e.g., creating posts):
- Channel Owner status (automatic permission for all channel actions)
- Suspension status (uses SuspendedRole if suspended)
- Channel-specific roles
- Channel default role
- Server default role
- For moderation actions:
- Channel Owner status (automatic permission for all moderation actions)
- Suspension status (uses SuspendedModRole if suspended)
- Elevated moderator status and role
- Default moderator role
- Server default moderator role
- For regular user actions (e.g., creating posts):
-
Permission Verification
- Once the appropriate role is determined, the system checks if that role grants the specific permission required for the action
- If the permission is granted, the action proceeds
- If the permission is denied, an error is returned
- Channel Owners always have full permissions within their channels
- Feedback Comments require moderator permissions (
canGiveFeedback
) rather than standard comment permissions - Suspended Users have limited permissions based on the Suspended roles
- The ability to create customized channel roles (changing what is allowed for standard users or moderators in a given channel) is a planned feature but is not currently available
- Currently, the permissions are defined in the server configuration
- All permission checks are enforced through GraphQL Shield middleware combined with custom rule resolvers
Permission checks are implemented in two main files:
hasChannelPermission.ts
- Handles regular user permissions for channel-specific actionshasChannelModPermission.ts
- Handles moderator permissions for moderation actions
These files share a similar logical flow but handle different types of roles and permissions.
The platform implements a real-time notification system for comments that alerts users when:
- Someone comments on their discussion
- Someone comments on their event
- Someone replies to their comment
The notification system is implemented using Neo4j GraphQL's subscription feature, which leverages Neo4j's Change Data Capture (CDC) capabilities. This approach offers several advantages over middleware-based approaches:
-
Reliability: The system uses Neo4j's native CDC mechanism to capture comment creation events directly from the database, ensuring no events are missed even during high loads.
-
Decoupling: The notification system operates independently from the HTTP request/response cycle, allowing the comment creation API to remain fast and responsive.
-
Resilience: The subscription-based approach can recover from temporary failures and automatically reconnect to the event stream.
-
Maintainability: With clear separation of concerns, the notification logic is isolated in a dedicated service that's easier to test and update.
-
Enabling Subscriptions: The Neo4j GraphQL schema is extended with the
@subscription
directive, enabling subscription capabilities. -
CommentNotificationService: A dedicated service class subscribes to the
commentCreated
event stream from Neo4j. -
Event Processing: When a new comment is created, the service:
- Receives the event with the new comment's basic information
- Queries the database for the full comment details and related entities
- Determines the notification type based on the comment context (discussion comment, event comment, or reply)
- Identifies the user who should receive the notification
- Generates both email and in-app notifications with appropriate links
-
Notification Delivery:
- Email notifications are sent via SendGrid
- In-app notifications are stored in the database and made available to users when they log in
Notifications include:
- Who created the comment
- The content being commented on (discussion, event, or parent comment)
- The comment text
- A direct link to view the comment using the permalink format
This approach ensures users are promptly notified of new interactions with their content while maintaining system performance and scalability.
I will fill out this section when the project is finished, or if someone expresses interest in collaborating on this project, whichever comes sooner. Anyone interested can contact me at [email protected].