Class Diagram - bounswe/bounswe2026group4 GitHub Wiki

alt

Note: Diagram rendered using PlantUML via the PlantUML Integration plugin in IntelliJ IDEA.

code
@startuml
skinparam style strictuml
skinparam classAttributeIconSize 0
skinparam class {
  BackgroundColor #FFF9E6
  BorderColor #CC8800
  ArrowColor #555555
  HeaderBackgroundColor #FFE599
}

title Local History Story Map - Class Diagram

' ─────────────────────────────────────────
' USER HIERARCHY
' ─────────────────────────────────────────

class User {
  -userId: String {id}
  -email: String
  -passwordHash: String
  -username: String
  -isUsernamePublic: Boolean
  -createdAt: Date
  -totalPoints: int
  +login(email: String, password: String): boolean
  +logout(): void
  +register(email: String, username: String, password: String): void
  +changePassword(oldPassword: String, newPassword: String): void
  +resetPassword(email: String): void
  +addPoints(points: int): void
  +deductPoints(points: int): void
  +getContributionCount(): int
  +deleteAccount(): void
}

class UserProfile {
  -profilePhoto: String
  -location: String
  -birthDate: Date
  -bio: String
  -isLocationPublic: Boolean
  -isBirthDatePublic: Boolean
  -isPhotoPublic: Boolean
  +updateProfile(): void
  +getPublicProfile(): UserProfile
  +validatePhoto(): boolean
}

class Admin {
  +reviewReport(reportId: String): void
  +removeContent(contentId: String, reason: String): void
  +banUser(userId: String): void
  +resolveReport(reportId: String, outcome: String): void
  +removeTag(tagId: String): void
  +reviewTags(): Tag[]
  +updateModerationPolicy(policy: String): void
}

' ─────────────────────────────────────────
' STORY
' ─────────────────────────────────────────

class Story {
  -storyId: String {id}
  -title: String
  -narrativeText: String
  -submissionDate: Date
  -status: StoryStatus
  -likeCount: int
  -saveCount: int
  -removalReason: String
  +publish(): void
  +remove(reason: String): void
  +delete(): void
  +edit(title: String, narrativeText: String): void
  +getLikeCount(): int
}

enum "<<enumeration>>\nStoryStatus" as StoryStatus {
  DRAFT
  PUBLISHED
  REMOVED
}

class StoryLocation {
  -locationId: String {id}
  -latitude: float
  -longitude: float
  -placeName: String
  -region: String
  +getCoordinates(): String
}

class TimePeriod {
  -timePeriodId: String {id}
  -startYear: int
  -endYear: int
  -approximatePeriod: String
  +getDisplayLabel(): String
}

class Tag {
  -tagId: String {id}
  -name: String
  -isPredefined: Boolean
  +validate(): boolean
}

' ─────────────────────────────────────────
' MAP / FEED / TIMELINE
' ─────────────────────────────────────────

interface MapHandler {
  +displayStoryPins(criteria: FilterCriteria): void
  +selectLocation(): StoryLocation
  +searchLocation(query: String): StoryLocation[]
  +getPreview(storyId: String): Story
  +zoomToRegion(region: String): void
  +geocodeAddress(address: String): StoryLocation
}

interface FeedHandler {
  +loadFeed(criteria: FilterCriteria): Story[]
  +loadNextPage(): Story[]
  +getDefaultFeed(userLocation: String): Story[]
  +sortByRecent(): Story[]
  +sortByPopular(): Story[]
}

interface TimelineHandler {
  +loadTimeline(region: String): TimePeriod[]
  +getStoriesForPeriod(timePeriodId: String): Story[]
  +filterByLocation(location: String): void
}

class EmailService {
  +sendVerificationCode(email: String): void
  +sendPasswordResetLink(email: String): void
}

' ─────────────────────────────────────────
' FILTER
' ─────────────────────────────────────────

class FilterCriteria {
  -keyword: String
  -locationFilter: String
  -startYear: int
  -endYear: int
  +addTagFilter(tag: Tag): void
  +clearFilters(): void
  +hasActiveFilters(): boolean
}

' ─────────────────────────────────────────
' MEDIA
' ─────────────────────────────────────────

class MediaFile {
  -mediaId: String {id}
  -fileType: MediaType
  -fileSize: long
  -filePath: String
  -uploadedAt: Date
  +validate(): boolean
  +getMetadata(): String
}

enum "<<enumeration>>\nMediaType" as MediaType {
  IMAGE
  AUDIO
  VIDEO
}

' ─────────────────────────────────────────
' INTERACTIONS
' ─────────────────────────────────────────

class Comment {
  -commentId: String {id}
  -text: String
  -createdAt: Date
  +create(): void
  +delete(): void
}

class Like {
  -likeId: String {id}
  -createdAt: Date
  +remove(): void
}

class SavedStory {
  -savedAt: Date
  +remove(): void
}

class Report {
  -reportId: String {id}
  -reason: ReportReason
  -description: String
  -createdAt: Date
  -status: ReportStatus
  -resolutionOutcome: String
  +submit(): void
  +resolve(outcome: String): void
}

enum "<<enumeration>>\nReportReason" as ReportReason {
  SPAM
  FALSE_CONTENT
  HARASSMENT
  PRIVACY_VIOLATION
  EXPLICIT_MEDIA
  OTHER
}

enum "<<enumeration>>\nReportStatus" as ReportStatus {
  PENDING
  RESOLVED
}

' ─────────────────────────────────────────
' GAMIFICATION
' ─────────────────────────────────────────

class Badge {
  -badgeId: String {id}
  -name: String
  -description: String
  -criteria: String
}

class UserBadge {
  -awardedAt: Date
}

class NotificationPreference {
  -preferenceId: String {id}
  -type: NotificationType
  -isEnabled: Boolean
  +toggle(): void
}

class Notification {
  -notificationId: String {id}
  -message: String
  -type: NotificationType
  -isRead: Boolean
  -createdAt: Date
  +markAsRead(): void
}

enum "<<enumeration>>\nNotificationType" as NotificationType {
  NEW_COMMENT
  NEW_LIKE
  MODERATION_ACTION
  STORY_REMOVED
  REPORT_RESOLVED
  BADGE_EARNED
}

' ─────────────────────────────────────────
' RELATIONSHIPS
' ─────────────────────────────────────────

' 1. Admin inherits from User
Admin --|> User

' User - Profile (composition: profile deleted with user)
User "1"*-- "1" UserProfile : has

' User submits stories (aggregation: stories anonymized, not deleted)
User "1" o-- "0..*" Story : submits

' Story structure
Story "1"*-- "1" StoryLocation : located at
Story "1"*-- "1" TimePeriod : covers
Story "0..*" -- "0..3" Tag : tagged with
Story "1" *-- "0..*" MediaFile : contains

' Interactions
User "1" *-down- "0..*" Comment : writes
Story "1" *-- "0..*" Comment : has

User "1" -- "0..*" Like : gives
Story "1" *-- "0..*" Like : receives

User "1" *-down- "0..*" SavedStory :has
Story "1" *-- "0..*" SavedStory : saved via

' Reporting
User "1" -- "0..*" Report : submits
Story "1" -- "0..*" Report : reported by
Comment "1" -- "0..*" Report : reported by

' Admin
Admin "1" *-up- "0..*" Report : "reviews"
Admin ..> Tag

' Gamification (UserBadge as association class)
User "1" -- "0..*" UserBadge : earns
Badge "1" -- UserBadge : awarded as
User "1" *-- "0..*" Notification : receives
User "1" *-- "0..*" NotificationPreference : configures

' Map
MapHandler ..> Story : displays
MapHandler ..> StoryLocation : reads/creates
User ..> EmailService : uses

' Feed
FeedHandler ..> FilterCriteria : filters with
FeedHandler ..> Story : returns

' Timeline
TimelineHandler ..> TimePeriod : navigates
TimelineHandler ..> Story : returns
TimelineHandler ..> FilterCriteria : filters with

' Filter
FilterCriteria "0..*" -- "0..*" Tag : filters by

' Enums (dependency)
Story ..> StoryStatus
MediaFile ..> MediaType
Report ..> ReportReason
Report ..> ReportStatus
Notification ..> NotificationType

@enduml

'''
⚠️ **GitHub.com Fallback** ⚠️