Data Model
This document describes the main data models used in the system, based on the Prisma schema.
User
- id: UUID, primary key
- email: Unique email address
- name: Optional display name
- passwordHash: Hashed password (nullable for social login users)
- createdAt, updatedAt: Timestamps
- Relations: userRoles, grantedRoles, incidents, auditLogs, reportComments, relatedFilesUploaded, assignedIncidents, avatar, passwordResetTokens, notifications, socialAccounts, notificationSettings, createdOrganizations, createdOrgInvites
Event
- id: UUID, primary key
- name: Event name
- slug: Unique, URL-safe identifier
- description: Optional event description
- startDate: Optional event start date
- endDate: Optional event end date
- website: Optional event website URL
- codeOfConduct: Optional code of conduct text
- contactEmail: Optional contact email
- isActive: Boolean (default: true)
- organizationId: Organization reference (required for organization-scoped events)
- createdAt, updatedAt: Timestamps
- Relations: organization, incidents, auditLogs, inviteLinks, eventLogo, notifications
UnifiedRole
- id: UUID, primary key
- name: Unique role name (system_admin, org_admin, org_viewer, event_admin, responder, reporter)
- scope: Role scope (system, organization, event)
- level: Hierarchy level (higher number = more permissions)
- description: Optional role description
- createdAt, updatedAt: Timestamps
- Relations: userRoles, eventInviteLinks
UserRole
- id: UUID, primary key
- userId: User reference
- roleId: UnifiedRole reference
- scopeType: Role scope (system, organization, event)
- scopeId: Scope identifier ('SYSTEM' for system, org_id for organization, event_id for event)
- grantedById: Optional reference to user who granted the role
- grantedAt: When the role was granted
- expiresAt: Optional role expiration date
- createdAt, updatedAt: Timestamps
- Unique: Combination of userId, roleId, scopeType, scopeId
Organization
- id: UUID, primary key
- name: Organization name
- slug: Unique, URL-safe identifier
- description: Optional organization description
- website: Optional organization website URL
- logoUrl: Optional logo URL
- settings: JSON string for flexible settings
- createdById: Reference to creating user
- createdAt, updatedAt: Timestamps
- Relations: events, createdBy, auditLogs, logo, inviteLinks
Incident
- id: UUID, primary key
- eventId: Event reference
- reporterId: User reference (nullable for anonymous)
- type: Report type enum (harassment, safety, other)
- title: Report title (required, max 70 chars)
- description: Report details
- state: Report state enum (submitted, acknowledged, investigating, resolved, closed)
- incidentAt: Optional date/time of the incident
- parties: Optional string listing parties involved (comma-separated or freeform)
- location: Optional string describing where the incident occurred
- contactPreference: Contact preference enum (email, phone, in_person, no_contact) with default 'email'
- assignedResponderId: string (nullable, UUID) — the user ID of the assigned responder (if any)
- assignedResponder: User (nullable) — the assigned responder user object (if any)
- severity: enum (
low
,medium
,high
,critical
, nullable) — severity/priority of the incident - resolution: string (optional) — freeform text describing the resolution of the incident
- createdAt, updatedAt: Timestamps
- Relations: comments, relatedFiles, notifications
IncidentComment
- id: UUID, primary key
- incidentId: Incident reference
- authorId: User reference (nullable for system comments)
- body: Comment text
- visibility: Comment visibility enum (public, internal)
- createdAt, updatedAt: Timestamps
- Relations: incident, author
RelatedFile
Represents a file uploaded as a related file for an incident.
- id: UUID, primary key
- incidentId: Incident reference
- filename: Original file name
- mimetype: File MIME type
- size: File size (bytes)
- data: File data (BLOB)
- uploaderId: User reference (nullable, for anonymous uploads)
- createdAt: Timestamp
- Relations: incident, uploader
EventLogo
- id: UUID, primary key
- eventId: Event reference (unique)
- filename: Original file name
- mimetype: File MIME type
- size: File size (bytes)
- data: File data (BLOB)
- createdAt: Timestamp
- Relations: event
UserAvatar
- id: UUID, primary key
- userId: User reference (unique)
- filename: Original file name
- mimetype: File MIME type
- size: File size (bytes)
- data: File data (BLOB)
- createdAt: Timestamp
- Relations: user
AuditLog
- id: UUID, primary key
- eventId: Event reference (nullable)
- userId: User reference (nullable)
- action: Action performed
- targetType: Type of target (e.g., User, Report)
- targetId: Target identifier
- timestamp: When the action occurred
- organizationId: Organization reference (nullable)
- Relations: event, user, organization
EventInviteLink
- id: UUID, primary key
- eventId: Event reference
- code: Unique invite code
- createdByUserId: User who created the invite (string, UUID)
- roleId: Role reference (role to assign when invite is redeemed)
- createdAt: Timestamp
- expiresAt: Optional expiration
- maxUses: Optional max uses
- useCount: Number of times used (default: 0)
- disabled: Boolean (default: false)
- note: Optional note
- Relations: event, role
SystemSetting
- id: UUID, primary key
- key: Unique setting key
- value: Setting value (string)
Current System Settings
- showPublicEventList: Boolean (stored as string) - Controls whether public event listing is shown on home page
PasswordResetToken
- id: UUID, primary key
- userId: User reference
- token: Unique reset token
- expiresAt: Token expiration date
- used: Boolean (whether token has been used)
- createdAt: Timestamp
- Relations: user
Notification
- id: UUID, primary key
- userId: User reference
- type: Notification type enum (incident_submitted, incident_assigned, incident_status_changed, incident_comment_added, event_invitation, event_role_changed, system_announcement)
- priority: Notification priority enum (low, normal, high, urgent)
- title: Notification title
- message: Notification message
- isRead: Boolean (default: false)
- readAt: Optional timestamp when notification was read
- eventId: Optional event reference
- incidentId: Optional incident reference
- actionData: Optional JSON string for action-specific data
- actionUrl: Optional URL to navigate to when notification is clicked
- createdAt, updatedAt: Timestamps
- Relations: user, event, incident
Enums
IncidentState
submitted
acknowledged
investigating
resolved
closed
IncidentType
harassment
safety
other
CommentVisibility
public
- visible to all involved (reporter, responders, admins)internal
- visible only to responders/admins
IncidentSeverity
low
medium
high
critical
ContactPreference
email
phone
in_person
no_contact
NotificationType
incident_submitted
- New incident submittedincident_assigned
- Report assigned to userincident_status_changed
- Report status changedincident_comment_added
- New comment on incidentevent_invitation
- Invited to eventevent_role_changed
- Role changed in eventsystem_announcement
- System-wide announcement
NotificationPriority
low
normal
high
urgent
SocialProvider
google
github
OrganizationRole
org_admin
- Organization administrator with full permissionsorg_viewer
- Organization viewer with read-only access
Organization Models
Organization
- id: UUID, primary key
- name: Organization name
- slug: Unique, URL-safe identifier
- description: Optional organization description
- website: Optional organization website URL
- logoUrl: Optional logo URL
- settings: Optional JSON string for flexible settings
- createdAt, updatedAt: Timestamps
- createdById: User reference (creator)
- Relations: createdBy, memberships, events, auditLogs, logo, inviteLinks
OrganizationMembership
- id: UUID, primary key
- organizationId: Organization reference
- userId: User reference
- role: Organization role enum (org_admin, org_viewer)
- createdAt: Timestamp
- createdById: User reference (who created the membership, nullable)
- Unique: Combination of organizationId and userId
- Relations: organization, user, createdBy
OrganizationLogo
- id: UUID, primary key
- organizationId: Organization reference (unique)
- filename: Original file name
- mimetype: File MIME type
- size: File size (bytes)
- data: File data (BLOB)
- createdAt: Timestamp
- Relations: organization
OrganizationInviteLink
- id: UUID, primary key
- organizationId: Organization reference
- code: Unique invite code
- createdByUserId: User who created the invite
- role: Organization role enum (org_admin, org_viewer)
- createdAt: Timestamp
- expiresAt: Optional expiration
- maxUses: Optional max uses
- useCount: Number of times used (default: 0)
- disabled: Boolean (default: false)
- note: Optional note
- Relations: organization, createdBy
SocialAccount
- id: UUID, primary key
- userId: User reference
- provider: Social provider enum (google, github)
- providerId: User's ID from the OAuth provider
- providerEmail: Email from the OAuth provider (nullable)
- providerName: Name from the OAuth provider (nullable)
- profileData: JSON string for basic profile data (nullable)
- createdAt, updatedAt: Timestamps
- Unique: Combination of provider and providerId, also userId and provider
- Relations: user
RateLimitAttempt
- id: UUID, primary key
- key: Rate limit key (e.g., "reset_attempt_email@example.com")
- type: Type of rate limit (e.g., "password_reset", "login_attempt")
- identifier: The identifier being rate limited (email, IP, etc.)
- expiresAt: Expiration timestamp
- createdAt: Timestamp
UserNotificationSettings
- id: UUID, primary key
- userId: User reference (unique)
- reportSubmittedInApp: Boolean (default: true)
- reportSubmittedEmail: Boolean (default: false)
- reportAssignedInApp: Boolean (default: true)
- reportAssignedEmail: Boolean (default: false)
- reportStatusChangedInApp: Boolean (default: true)
- reportStatusChangedEmail: Boolean (default: false)
- reportCommentAddedInApp: Boolean (default: true)
- reportCommentAddedEmail: Boolean (default: false)
- eventInvitationInApp: Boolean (default: true)
- eventInvitationEmail: Boolean (default: false)
- eventRoleChangedInApp: Boolean (default: true)
- eventRoleChangedEmail: Boolean (default: false)
- systemAnnouncementInApp: Boolean (default: true)
- systemAnnouncementEmail: Boolean (default: false)
- createdAt, updatedAt: Timestamps
- Relations: user
For the full schema, see backend/prisma/schema.prisma
.