Skip to content

Class diagram

Fredrik Jonathan Marjoni edited this page Apr 21, 2026 · 9 revisions

Class-diagram

image

@startuml
' ===== HmH Class Diagram =====

' ============================== Domain Layer ==============================
abstract class User {
  - int userId
  - String firstName
  - String lastName
  - String email
  - String passwordHash
  + User(userId, firstName, lastName, email, passwordHash)
  + getUserId() : int
  {abstract} + getRole() : String
  + getFirstName() : String
  + getLastName() : String
  + getEmail() : String
  + getPasswordHash() : String
  + verifyPassword(password : char[]) : boolean
}

class Customer extends User {
  - List<Integer> preferences
  + Customer(userId, firstName, lastName, email, passwordHash)
  + getRole() : String
  + getPreferences() : List<Integer>
  + addPreference(orgNumber : int) : void
  + removePreference(orgNumber : int) : void
}

class Organization <<record>> {
  - int orgNumber
  - String name
  - boolean trusted
  - String websiteUrl
  - boolean isPreApproved
  - String description
  - String logoUrl
  + Organization(orgNumber, name, trusted, websiteUrl, isPreApproved, description, logoUrl)
  + orgNumber() : int
  + name() : String
  + trusted() : boolean
  + websiteUrl() : String
  + isPreApproved() : boolean
  + description() : String
  + logoUrl() : String
}

class Donation <<record>> {
  - int donationId
  - int userId
  - int organizationId
  - BigDecimal amount
  - Timestamp date
  - String paymentMethod
  + Donation(donationId, userId, organizationId, amount, date, paymentMethod)
  + donationId() : int
  + userId() : int
  + organizationId() : int
  + amount() : BigDecimal
  + date() : Timestamp
  + paymentMethod() : String
}

class AppState {
  - User currentUser
  - BigDecimal currentDonationAmount
  - Organization currentOrganization
  + getCurrentUser() : User
  + setCurrentUser(user : User) : void
  + getCurrentOrganization() : Organization
  + setCurrentOrganization(organization : Organization) : void
  + getCurrentDonationAmount() : BigDecimal
  + setCurrentDonationAmount(amount : BigDecimal) : void
}

' ===== Scraper Layer =====
class OrganizationScraper {
  - Map<String, String> descriptionCache
  - Map<String, String> logoCache
  + OrganizationScraper()
  + fetchDescription(pageUrl : String) : String
  + fetchLogoUrl(pageUrl : String) : String
  # parseDescription(doc : Document) : String
  # parseLogoUrl(doc : Document) : String
}

' ===== Repository Layer =====
abstract class Repository<K, V> {
  # Map<K, V> content
  # Repository(Map<K, V> content)
  + getContent() : Map<K, V>
}

abstract class DBRepository<K, V> extends Repository {
  # Map<K, V> contentLock
  # DBRepository(Map<K, V> content)
  # {abstract} updateContentLock() : void
  + {abstract} addContent(value : V) : boolean
  + {abstract} export() : List<Object[]>
}

class UserRepository extends DBRepository {
  + {static} ROLE_CUSTOMER : String
  + UserRepository(rows : List<Object[]>)
  # updateContentLock() : void
  + export() : List<Object[]>
  + getUsers() : HashMap<Integer, User>
  + getUserById(userId : int) : User
  + getNextUserId() : int
  + addContent(user : User) : boolean
  + findUserByEmail(email : String) : User
}

class DonationRepository extends DBRepository {
  - HashMap<Integer, Donation> content
  + DonationRepository(rows : List<Object[]>)
  # updateContentLock() : void
  + export() : List<Object[]>
  + getDonationById(donationId : int) : Donation
  + getNextDonationId() : int
  + getAllDonations() : Map<Integer, Donation>
  + addContent(donation : Donation) : boolean
  + sortByDate() : HashMap<Integer, Donation>
  + sortByAmount() : HashMap<Integer, Donation>
  + filterByOrganization(orgNumber : int) : HashMap<Integer, Donation>
  + filterByUser(userId : int) : HashMap<Integer, Donation>
}

class OrganizationRepository extends Repository {
  - HashMap<Integer, Organization> grandMap
  - OrganizationScraper scraper
  + OrganizationRepository(input : Object[], scraper : OrganizationScraper)
  + export() : Object[]
  + getTrustedOrganizations() : Map<Integer, Organization>
  + findByOrgNumber(orgNumber : int) : Organization
  + findByOrgName(name : String) : Organization
}

' ===== Service Layer =====
class UserService {
  - UserRepository userRepository
  + UserService(userRepository : UserRepository)
  + getUserRepository() : UserRepository
  + registerUser(role, firstName, lastName, email, passwordHash) : boolean
  + login(email : String, password : char[]) : User
  + getUserByEmail(email : String) : User
}

class DonationService {
  - DonationRepository donationRepository
  - OrganizationRepository organizationRepository
  + DonationService(donationRepository, organizationRepository)
  + getDonationRepository() : DonationRepository
  + getOrganizationRepository() : OrganizationRepository
  + donate(customer : Customer, orgNumber : int, amount : BigDecimal, paymentMethod : String) : boolean
}

class OrganizationService {
  - OrganizationRepository organizationRepository
  - OrganizationScraper scraper
  + OrganizationService(organizationRepository : OrganizationRepository, scraper : OrganizationScraper)
  + getOrganizationRepository() : OrganizationRepository
  + getTrustedOrganizations() : Map<Integer, Organization>
  + findByOrgNumber(orgNumber : int) : Organization
  + findByOrgName(name : String) : Organization
  + fetchLogoUrl(pageUrl : String) : String
  + getTrustedOrganizationsWithLogos() : Map<Integer, Organization>
  + getTrustedOrganizationsWithLogosAsync() : CompletableFuture<Map<Integer, Organization>>
}

' ===== Wrapper Layer =====
abstract class Wrapper {
  # Wrapper()
  + {abstract} importData() : boolean
  + {abstract} getData() : Object
}

class OrgApiWrapper extends Wrapper {
  - Object[] data
  - HttpClient client
  - HttpRequest request
  + OrgApiWrapper(urlString : String)
  + importData() : boolean
  + getData() : Object[]
}

class DbWrapper {
  # Connection connection
  - String connectionString
  - List<Object[]> users
  - List<Object[]> donations
  - Logger logger
  + DbWrapper(test : boolean)
  + connect() : boolean
  + disconnect() : boolean
  + importUsers() : List<Object[]>
  + exportUsers(data : List<Object[]>) : int
  + fetchAllDonations() : List<Object[]>
  + importDonations(user_id : int) : List<Object[]>
  + exportDonations(data : List<Object[]>) : int
}

' ============================== Frontend Layer ==============================
class App extends Application {
  - DbWrapper dbWrapper
  - UserRepository userRepository
  - DonationRepository donationRepository
  - BorderPane root
  - AppState appState
  - NavigationController nav
  - Logger logger
  + main(args : String[]) : void
  + init() : void
  + start(stage : Stage) : void
  + stop() : void
}

' ========================= Controllers =========================
class NavigationController {
  - BorderPane root
  - Header header
  - LoginHeader loginHeader
  - AppState appState
  - LoginController loginController
  - DonationController donationController
  - OrganizationController organizationController
  + NavigationController(root, appState, userService, donationService, organizationService)
  + showHomePage() : void
  + showLoginPage() : void
  + showSignInPage() : void
  + showPaymentCompletePage() : void
  + showCausesPage() : void
  + showOrganizationPage() : void
  + showDonationPage() : void
  + showAboutUsPage() : void
  + showUserPage() : void
}

class LoginController {
  - AppState appState
  - NavigationController nav
  - UserService userService
  + LoginController(appState, nav, userService)
  + handleSignIn(view : SignInPageView, firstName, lastName, email, passwordChars) : void
  + handleLogin(view : LoginPageView, email, passwordChars) : void
  + handleLogout() : void
}

class DonationController {
  - AppState appState
  - NavigationController nav
  - DonationService service
  + DonationController(appState, nav, service)
  + getUserDonations(userId : int) : Map<Integer, Donation>
  + getUniqueOrgs() : Set<Integer>
  + handleDonate() : void
}

class OrganizationController {
  - AppState appState
  - NavigationController nav
  - OrganizationService service
  + OrganizationController(appState, nav, service)
  + getOrgById(orgId : int) : Organization
  + getTrustedOrgs() : Map<Integer, Organization>
  + getOrganizationsWithLogosAsync() : CompletableFuture<Map<Integer, Organization>>
}

class AuthController {
  - AppState appState
  - NavigationController nav
  - UserService userService
  + AuthController(appState, nav, userService)
  + handleSignUp(view : SignUpPageView, firstName, lastName, email, passwordChars) : void
  + handleLogin(view : LoginPageView, email, passwordChars) : void
  + handleLogout() : void
  + setCurrentUser(user : User) : void
  + getCurrentUser() : User
}

' ========================= Views =========================
class Header  {
  - NavigationController controller
  + Header(controller : NavigationController)
  - getLogoSection() : StackPane
  - getNavBar() : HBox
  - getProfileSection() : StackPane
}

class LoginHeader  {
  + LoginHeader()
}

class LoginPageView  {
  - AppState appState
  - NavigationController nav
  - LoginController loginController
  - TextField emailField
  - PasswordField passwordField
  - Label errorLabel
  + LoginPageView(appState, nav, loginController)
  + getEmail() : String
  + getPassword() : char[]
  + showError(message : String) : void
}

class SignInPageView  {
  - AppState appState
  - NavigationController nav
  - LoginController loginController
  + SignInPageView(appState, nav, loginController)
  + showError(message : String) : void
}

class HomePageView  {
  - AppState appState
  - NavigationController nav
  + HomePageView(appState, nav)
}

class CausesPageView  {
  - AppState appState
  - NavigationController nav
  - OrganizationController orgController
  - GridPane organizationGrid
  - Map<Integer, Organization> allOrganizations
  + CausesPageView(appState, nav, orgController)
  - createBody() : ScrollPane
  - createSearchSection() : HBox
  - createOrganizationSection(searchTerm : String) : GridPane
  - filterOrganizations(searchTerm : String) : Map<Integer, Organization>
  - updateOrganizationGrid(searchTerm : String) : void
}

class OrganizationCard {
  - AppState appState
  - Organization organization
  - NavigationController nav
  + OrganizationCard(appState, nav, org, img)
  - imageContainer(img : String) : StackPane
  - orgName(text : String) : Text
  - checkMarkContainer() : StackPane
}

class OrganizationPageView  {
  - AppState appState
  - NavigationController nav
  - DonationController donationController
  + OrganizationPageView(appState, nav, donationController)
}

class DonationPageView  {
  - AppState appState
  - NavigationController nav
  - DonationController donationController
  + DonationPageView(appState, nav, donationController)
}

class PaymentCompletePageView  {
  - NavigationController nav
  + PaymentCompletePageView(nav)
}

class UserPageView  {
  - AppState appState
  - NavigationController nav
  - LoginController loginController
  - DonationController donationController
  - OrganizationController organizationController
  + UserPageView(appState, nav, loginController, donationController, organizationController)
}
' ===== Utility Classes =====
class ParameterValidator {
  + {static} objectChecker(obj : Object, name : String) : void
  + {static} stringChecker(str : String, name : String) : void
  + {static} intChecker(num : int, name : String) : void
}

' ===== Relationships =====

' App initialization (composition - App owns these)
App *-- DbWrapper : creates
App *-- OrgApiWrapper : creates
App *-- OrganizationScraper : creates
App *-- UserRepository : creates
App *-- DonationRepository : creates
App *-- OrganizationRepository : creates
App *-- UserService : creates
App *-- DonationService : creates
App *-- OrganizationService : creates
App *-- AppState : creates
App *-- NavigationController : creates

' Scraper integration
OrganizationRepository --> OrganizationScraper : uses (dependency injection)
OrganizationService --> OrganizationScraper : uses (dependency injection)

' NavigationController creates and holds controllers (composition)
NavigationController *-- LoginController : creates
NavigationController *-- DonationController : creates
NavigationController *-- OrganizationController : creates
NavigationController *-- Header : creates
NavigationController *-- LoginHeader : creates

' Controllers use AppState (dependency)
LoginController ..> AppState : uses
DonationController ..> AppState : uses
OrganizationController ..> AppState : uses

' Controllers use NavigationController for navigation (dependency)
LoginController ..> NavigationController : uses
DonationController ..> NavigationController : uses
OrganizationController ..> NavigationController : uses

' AuthController relationships
NavigationController *-- AuthController : creates
AuthController ..> AppState : uses
AuthController ..> NavigationController : uses
AuthController ..> UserService : uses

' ParameterValidator is used throughout (utility class)
UserRepository ..> ParameterValidator : uses
UserService ..> ParameterValidator : uses
DonationRepository ..> ParameterValidator : uses
OrganizationRepository ..> ParameterValidator : uses
LoginController ..> ParameterValidator : uses
AuthController ..> ParameterValidator : uses

' Views receive dependencies (dependency)
Header ..> NavigationController : uses
LoginPageView ..> NavigationController : uses
LoginPageView ..> LoginController : uses
LoginPageView ..> AppState : uses

SignInPageView ..> NavigationController : uses
SignInPageView ..> LoginController : uses
SignInPageView ..> AppState : uses

HomePageView ..> NavigationController : uses
HomePageView ..> AppState : uses

CausesPageView ..> NavigationController : uses
CausesPageView ..> OrganizationController : uses
CausesPageView ..> AppState : uses

OrganizationCard ..> NavigationController : uses
OrganizationCard ..> AppState : uses

OrganizationPageView ..> NavigationController : uses
OrganizationPageView ..> DonationController : uses
OrganizationPageView ..> AppState : uses

DonationPageView ..> NavigationController : uses
DonationPageView ..> DonationController : uses
DonationPageView ..> AppState : uses

PaymentCompletePageView ..> NavigationController : uses

UserPageView ..> NavigationController : uses
UserPageView ..> LoginController : uses
UserPageView ..> DonationController : uses
UserPageView ..> OrganizationController : uses
UserPageView ..> AppState : uses

' Controllers use Services (dependency)
LoginController ..> UserService : uses
DonationController ..> DonationService : uses
OrganizationController ..> OrganizationService : uses

' Services use Repositories (dependency)
UserService ..> UserRepository : uses
DonationService ..> DonationRepository : uses
DonationService ..> OrganizationRepository : uses
OrganizationService ..> OrganizationRepository : uses

' Services create domain objects (association)
UserService --> Customer : creates
DonationService --> Donation : creates

' Repositories manage domain objects (aggregation)
UserRepository o-- User : manages
DonationRepository o-- Donation : manages
OrganizationRepository o-- Organization : manages

' Domain relationships
Donation --> Customer : donated by
Donation --> Organization : donated to
Customer o-- Organization : preferences
Customer --|> User : extends

DbWrapper ..> UserRepository : «data flow»
DbWrapper ..> DonationRepository : «data flow»
OrgApiWrapper ..> OrganizationRepository : «data flow»
@enduml