@startuml skinparam { BackgroundColor LightYellow ArrowColor Black Shadowing false BorderColor Black } package "Router" { class "AltoRouter" { +match() } class "Request" { + method : string + uri : string + headers : array + body : string + getParameter(string) : string } class "Response" { + statusCode : int + headers : array + body : string + setHeader(string, string) : void + setContent(string) : void } class "RedirectResponse" { + targetUrl : string + setTargetUrl(string) : void } interface "Action" { + execute(Request) : Response } } package "Controllers" { abstract class "BaseController" { - redirect(string, int) : RedirectResponse - redirectToRoute(string, array, int) : RedirectResponse - renderView(string, array) : string - render(string, array, Response) : Response - doRenderView(string, string?, array, string) : string - doRender(string, string?, array, Response, string) : Response + abstract index() + abstract show($id) } class "AthleteController"{ + index() + show($id) + create() + update($id) +viewProfile() +updateProfile() } class HeartRateController { +model: HeartRateMonitor +view: IView +fetchAndDisplayData(): void } class "CoachController" { + index() + show($id) +assignTraining() } } package "Services" { class "AthleteService" { +createAthlete() +updateProfile() } class "TrainingService" { +assignTraining() } interface "NotificationStrategy" { +sendNotification() } class "EmailNotification" { } class "PushNotification" { } } package "Factories" { class "AthleteFactory" { +createAthlete() : Athlete } class WatchFactory { +createWatch(model: string, user: User): Watch } } package "Models" { class "Athlete" { + ID_Athlete : int + Name : string + Email : string + Password : string + PublicProfile : text + WeightHistory : string + Goals : text +registerObserver() +removeObserver() +notifyObservers() } interface "Observer" { +update() } class "Coach" extends Athlete { } class "Notification" implements Observer { +update() } interface IHeartRateDataProvider { +getHeartRateData(): HeartRateData } interface IHeartRateDataObserver { +update(data: HeartRateData): void } class HeartRateData { +dataId: int +timestamp: datetime +heartRate: int +location: Location +activity: Activity } class Location { +latitude: double +longitude: double +altitude: double } class Watch extends SourceData{ } interface IHeartRateZoneProvider { +getHeartRateZones(): HeartRateZone[] } class HeartRateZoneProvider implements IHeartRateZoneProvider { +getHeartRateZones(): HeartRateZone[] } class HeartRateMonitor implements IHeartRateDataProvider, Subject { +deviceId: int +name: string +serialNumber: string +user: User +heartRateData: HeartRateData[] +attach(observer: Observer): void +detach(observer: Observer): void +notifyObservers(): void +getHeartRateData(): HeartRateData } class "Activity" { + ID_Activity : int + Type : string + Date : date + StartTime : time + EndTime : time + GPS_Position : string + Altitude : float + File : file } class "HeartRate" { + ID_HR : int + Time : time + BPM : int + Variability : float + Variance : float + StandardDeviation : float + Average : float + Max : int + Min : int } class "Statistic" { + ID_Statistic : int + TotalDistance : float + TotalTime : time + AverageHR : int + MaxHR : int + CaloriesBurned : float + PersonalRecords : string } class "Training" { + ID_Training : int + Date : date + Description : text + Exercises : text + Feedback : text } class "Notification" { + ID_Notification : int + Message : text + Date : date + Status : enum + Type : string + Urgency : enum } class "Event" { + ID_Event : int + Name : string + Description : text + Date : date + Location : string } class "SourceData" { + ID_Source : int + Type : string + Model : string + Precision : enum + PurchaseDate : date + LastUseDate : date } } package "Repositories" { interface "Repository" { +findByID() +save() +delete() } class "AthleteRepository" implements Repository { } } AltoRouter --> AthleteController AthleteController --> AthleteService AthleteService --> AthleteFactory AthleteFactory --> Athlete AthleteService --> NotificationStrategy Athlete --> AthleteRepository : uses Athlete -right-> Observer : notifies Notification --> Athlete : observes @enduml