@startuml ' Type Symbol ' Zero or One |o-- ' Exactly One ||-- ' Zero or Many }o-- ' One or Many }|-- skinparam linetype ortho entity User { * int id <> * String email * String password * boolean verified * long created_at } entity SubscriptionAction { * int id <> * int user_id * long timestamp * int subscription_id * boolean added } entity Subscription { * int id <> * String url * long timestamp * String title } entity Episode { * int id <> * int guid <> * String url * String title * int total * int subscription_id } note right Wenn der Client eine GUID aus dem Feed mitsendet, wird diese statt der URL verwendet um die Episode zu finden. So wird die Episode auch noch gefunden, nachdem sich die URL geändert hat. end note note bottom of Episode Wenn für die Episoden-URL einer EpisodeAction noch keine Episode in der Datenbank steht, dann schreibe dafür ein Dummy-Objekt in Datenbank und lade asynchron die Episoden der Subscription. Ersetze dann die Dummy-Objekte durch die Episoden und setze den Timestamp der Subscription auf die aktuelle Zeit. Um DoS-Angriffe auf den Backend-Server abzuwenden, können die Episoden einer Subscription erst nach einer Stunde erneut gefetched werden. Bis dahin werden für EpisodeActions, die sich auf noch nicht geladene Episoden beziehen, nur Dummy-Objekte für die Episoden in die Datenbank geschrieben. Es sei noch darauf hingewiesen, dass diese Dummy-Episoden bei Anfragen nicht mit ausgegeben werden. end note entity EpisodeAction { * int id <> * int user_id * int episode_id * long timestamp * int action * int started * int position } note right Speichere für jede Episode nur letzte Play-Action. endnote User ||--o{ EpisodeAction User ||--o{ SubscriptionAction SubscriptionAction }|--|| Subscription EpisodeAction }|--|| Episode Subscription ||-right-|{ Episode @enduml