A website for browsing photos and albums delivered via Typicode API.
The real purpose of this project is to demonstrate building a modern frontend application architecture with SvelteKit and Hexagonal / Clean Architecture principles.
Read the guide in my blog where I'm building the application and explaining the design process behind it.
See the demo application on Netlify.
task installtask devtask testOverview of the software architecture and design is visualised in a Mermaid diagram below.
classDiagram
    direction
    class SvelteKit {
        <<Framework>>
    }
    class Layout {
        load(LayoutParams params) LayoutData
    }
    class Page {
        ssr : boolean
        csr : boolean
        load(RouteParams params) PageData
    }
    class Component
    class Script
    class HTML
    class Style
    class PhotoBrowser {
        <<Service>>
        withLimit(int limit) self
        loadPhotos() Array~Photo~
        loadPhoto(int id) Photo
        loadFromAlbum(int albumId) Array~Photo~
        groupPhotosByAlbum() Array~Album~
    }
    class PhotoCalculator {
        <<Service>>
        parseFullSize() Tuple~int~
        parseThumbnailSize() Tuple~int~
    }
    class Photo {
        <<Entity>>
        id : int
        albumId : int
        title : string
        url : URL
        thumbnailUrl : URL
    }
    class PhotoGateway~T~ {
        <<interface>>
        fetchPhotos(FetchParams args) Array~T~
        fetchPhoto(int id) T
        fetchPhotosByAlbumId(int albumId, FetchParams params) Dictionary~T~
    }
    class APIGateway~T~ {
        <<Adapter>>
    }
    class Typicode {
        <<REST API>>
    }
    class Vitest {
        <<Test Framework>>
    }
    class FakeGateway~T~ {
        <<Test Double>>
    }
    class FakerJS {
        <<library>>
    }
    SvelteKit "1" --> "1" PhotoBrowser : uses
    SvelteKit "1" --> "1" PhotoCalculator : uses
    SvelteKit "1" --> "1" Layout : loads
    Layout "1" --> "*" Page : contains
    Page "1" --o "*" Component : renders
    Component "1" --> "1" Script : contains
    Component "1" --> "1" HTML : contains
    Component "1" --> "1" Style : contains
    PhotoBrowser --> APIGateway : uses
    Vitest --> FakeGateway : uses
    PhotoGateway "1" --> "*" Photo : fetches
    APIGateway --|> PhotoGateway : implements
    APIGateway ..> Typicode : uses
    FakeGateway --|> PhotoGateway : implements
    FakeGateway ..> FakerJS : uses