# maxbrc/photo-portfolio architecture

> Architecture diagram of the GitHub repository maxbrc/photo-portfolio, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-16). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/maxbrc/photo-portfolio
- Repository: https://github.com/maxbrc/photo-portfolio

## Overview

1. **Overall shape**
   - This repo is a three-part application: a **Go backend**, a **TypeScript/React frontend**, and a **MariaDB database**.
   - In production, everything is containerized with Docker Compose; the backend is the main externally exposed service, while the frontend is a separate Node-based runtime/build target.

2. **Backend entrypoint and responsibilities**
   - The backend starts from `backend/cmd/main.go`.
   - It wires configuration, database access, HTTP routes, authentication, album/image services, and filesystem-backed site data.
   - The backend is responsible for all business logic and all privileged admin operations.

3. **HTTP API layer**
   - `backend/api/routes.go` and `backend/api/handlers/*` define the REST surface.
   - The handlers are split by resource and action: albums, images, users, login/refresh, site content, photo serving, and cleanup.
   - This suggests a classic request flow: HTTP handler parses request → internal service package executes logic → DB/filesystem response is returned.

4. **Domain/service boundaries in the backend**
   - `backend/internal/albums`, `backend/internal/images`, and `backend/internal/auth` hold the core application logic.
   - These packages keep HTTP concerns separate from persistence and domain behavior.
   - `backend/internal/models` provides shared data shapes used across handlers, DB, and services.

5. **Persistence layer**
   - `backend/internal/db/*` is the database access layer for users, albums, and images.
   - The app uses **MariaDB/MySQL** for structured data such as users, album metadata, image metadata, and assignments.
   - `db/init.go` indicates the backend likely initializes or verifies schema on startup rather than relying on a separate migration system.

6. **Authentication and authorization**
   - Authentication is handled in `backend/internal/auth`.
   - Password hashing and JWT support are explicit, and the README says JWTs are signed with an **Ed25519 private key seed** stored in the mounted `data/secrets` directory.
   - The API includes login and refresh-token endpoints, so auth is token-based and likely protects admin routes.

7. **Filesystem-backed application state**
   - Not all state lives in the database. The README and code structure show a mounted `data` directory containing:
     - `config.json` for site/homepage content
     - `photos/` for actual image files
     - `secrets/` for JWT signing material
   - `backend/api/handlers/get_site_content.go` and `patch_site_content.go` indicate the homepage/config data is edited through the API but stored on disk, not in MariaDB.

8. **Image pipeline**
   - Images are managed through `backend/internal/images` and the related handlers.
   - The storage layout distinguishes between `photos/originals` and `photos/derivatives`.
   - The README describes derivative filenames as resized/cached WebP variants, so image requests likely flow through backend logic that serves originals or generated derivatives and may create/update cached versions.

9. **Album and gallery model**
   - Albums appear to be a first-class domain with CRUD plus image assignment endpoints.
   - The presence of `get_albums_assignments.go` and `put_albums_assignments.go` indicates a separate relationship between albums and images, not just flat metadata.
   - Public gallery browsing likely consumes album/image metadata from the backend and image URLs from the photo subsystem.

10. **Frontend structure**
   - The frontend is a React + TypeScript app under `frontend/client/src`.
   - It is split into public pages/components (`Home`, `Gallery`, `Albums`, `ImageBrowser`, `Header`, `Footer`, `Login`, `Impressum`) and admin screens (`Admin*` components).
   - This suggests one frontend codebase with two major navigation areas: visitor-facing portfolio and authenticated administration.

11. **Frontend build/runtime split**
   - `frontend/webpack.*.js` handles the client bundle build.
   - `frontend/server/src/index.tsx` and `build-server.mjs` indicate there is also a server-side Node build path, likely used to serve or render the frontend in production.
   - The frontend therefore has both a browser bundle and a server runtime, even though the backend remains the primary API/data authority.

12. **Deployment and runtime topology**
   - Docker Compose wires three services: `db`, `backend`, and `frontend`.
   - The backend container gets `DB_HOST=db` and `NODE_URL=http://frontend:3010`, while the frontend depends on the backend.
   - Persistent state is split across a MariaDB volume and a mounted application-data directory for config, photos, and secrets.

13. **Key architectural boundary**
   - The most important boundary in this repository is between **structured data in MariaDB** and **unstructured/media/site state on disk**.
   - The backend bridges both worlds: it reads/writes DB entities, manages authentication, and also serves/manipulates files under the mounted data directory.

Main entry points: [`backend/cmd/main.go`](https://github.com/maxbrc/photo-portfolio/blob/main/backend/cmd/main.go) (Main), [`backend/api/handlers`](https://github.com/maxbrc/photo-portfolio/tree/main/backend/api/handlers) (Handlers), [`backend/internal/db`](https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/db) (DB layer), [`backend/internal/images`](https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/images) (Images)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_backend["Backend"]
  node_backend_cmd_main(("Main<br/>go entrypoint<br/>[main.go]"))
  node_backend_routes["Routes<br/>http router<br/>[routes.go]"]
  node_backend_api_handlers["Handlers"]
  node_backend_albums["Albums<br/>domain service"]
  node_backend_images["Images<br/>media service"]
  node_backend_auth["Auth"]
  node_backend_db[("DB layer<br/>mysql access")]
  node_backend_models["Models<br/>shared schema"]
  node_backend_config["Config<br/>[config.go]"]
end

subgraph group_frontend["Frontend"]
  node_frontend_app(("App<br/>react entry<br/>[App.tsx]"))
  node_frontend_public["Public UI<br/>visitor pages"]
  node_frontend_admin["Admin UI<br/>admin screens<br/>[Admin.tsx]"]
  node_frontend_types["Client types<br/>typescript models"]
  node_frontend_bundle["Browser build<br/>webpack build<br/>[webpack.prod.js]"]
  node_frontend_server["SSR server<br/>node runtime<br/>[index.tsx]"]
end

subgraph group_deployment["Runtime"]
  node_compose["Compose<br/>docker orchestration"]
  node_mariadb[("MariaDB<br/>database service")]
end

node_backend_cmd_main -->|"loads"| node_backend_config
node_backend_cmd_main -->|"mounts"| node_backend_routes
node_backend_cmd_main -->|"initializes"| node_backend_db
node_backend_cmd_main -->|"uses"| node_backend_auth
node_backend_cmd_main -->|"uses"| node_backend_albums
node_backend_cmd_main -->|"uses"| node_backend_images
node_backend_routes -->|"dispatches to"| node_backend_api_handlers
node_backend_api_handlers -->|"calls"| node_backend_albums
node_backend_api_handlers -->|"calls"| node_backend_images
node_backend_api_handlers -->|"calls"| node_backend_auth
node_backend_api_handlers -->|"reads/writes"| node_backend_db
node_backend_api_handlers -->|"marshals"| node_backend_models
node_backend_albums -->|"persists via"| node_backend_db
node_backend_images -->|"persists via"| node_backend_db
node_backend_images -->|"uses"| node_backend_models
node_backend_auth -->|"loads users"| node_backend_db
node_frontend_app -->|"navigates to"| node_frontend_public
node_frontend_app -->|"navigates to"| node_frontend_admin
node_frontend_public -->|"uses"| node_frontend_types
node_frontend_admin -->|"uses"| node_frontend_types
node_frontend_bundle -->|"builds"| node_frontend_app
node_frontend_server -->|"serves"| node_frontend_app
node_compose -->|"runs"| node_backend_cmd_main
node_compose -->|"runs"| node_frontend_server
node_compose -->|"provides"| node_mariadb
node_backend_db -->|"connects to"| node_mariadb
node_frontend_server -.->|"API client"| node_backend_routes

click node_backend_cmd_main "https://github.com/maxbrc/photo-portfolio/blob/main/backend/cmd/main.go"
click node_backend_routes "https://github.com/maxbrc/photo-portfolio/blob/main/backend/api/routes.go"
click node_backend_api_handlers "https://github.com/maxbrc/photo-portfolio/tree/main/backend/api/handlers"
click node_backend_albums "https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/albums"
click node_backend_images "https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/images"
click node_backend_auth "https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/auth"
click node_backend_db "https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/db"
click node_backend_models "https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/models"
click node_backend_config "https://github.com/maxbrc/photo-portfolio/blob/main/backend/config/config.go"
click node_frontend_app "https://github.com/maxbrc/photo-portfolio/blob/main/frontend/client/src/components/App.tsx"
click node_frontend_public "https://github.com/maxbrc/photo-portfolio/tree/main/frontend/client/src/components"
click node_frontend_admin "https://github.com/maxbrc/photo-portfolio/blob/main/frontend/client/src/components/Admin.tsx"
click node_frontend_types "https://github.com/maxbrc/photo-portfolio/tree/main/frontend/client/src/types"
click node_frontend_bundle "https://github.com/maxbrc/photo-portfolio/blob/main/frontend/client/webpack.prod.js"
click node_frontend_server "https://github.com/maxbrc/photo-portfolio/blob/main/frontend/server/src/index.tsx"
click node_compose "https://github.com/maxbrc/photo-portfolio/blob/main/docker/docker-compose.dev.yml"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_backend_cmd_main,node_backend_routes,node_backend_api_handlers,node_backend_albums,node_backend_images,node_backend_auth,node_backend_db,node_backend_models,node_backend_config toneBlue
class node_frontend_app,node_frontend_public,node_frontend_admin,node_frontend_types,node_frontend_bundle,node_frontend_server toneAmber
class node_compose,node_mariadb toneMint
```

## Components

### Backend

Go API, auth, domain logic, and persistence bridge.

- [Main](https://github.com/maxbrc/photo-portfolio/blob/main/backend/cmd/main.go): go entrypoint · Starts the backend and wires configuration, routes, services, and storage. · `backend/cmd/main.go`
- [Routes](https://github.com/maxbrc/photo-portfolio/blob/main/backend/api/routes.go): http router · Defines the API surface and connects handlers to endpoints. · `backend/api/routes.go`
- [Handlers](https://github.com/maxbrc/photo-portfolio/tree/main/backend/api/handlers): http handlers · REST handlers for albums, images, users, login/refresh, site content, photo serving, and cleanup. · `backend/api/handlers`
- [Albums](https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/albums): domain service · Album CRUD and album-image assignment workflows. · `backend/internal/albums`
- [Images](https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/images): media service · Image upload, retrieval, update, delete, and cleanup logic including derivatives. · `backend/internal/images`
- [Auth](https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/auth): auth service · Password hashing, JWT creation/verification, and user auth flows. · `backend/internal/auth`
- [DB layer](https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/db): mysql access · MariaDB/MySQL persistence for users, albums, and images. · `backend/internal/db`
- [Models](https://github.com/maxbrc/photo-portfolio/tree/main/backend/internal/models): shared schema · Shared application data shapes used across handlers, services, and persistence. · `backend/internal/models`
- [Config](https://github.com/maxbrc/photo-portfolio/blob/main/backend/config/config.go): config loader · Loads backend configuration and defaults. · `backend/config/config.go`

### Frontend

React/TypeScript app with browser and server build targets.

- [App](https://github.com/maxbrc/photo-portfolio/blob/main/frontend/client/src/components/App.tsx): react entry · Top-level client application shell and routing. · `frontend/client/src/components/App.tsx`
- [Public UI](https://github.com/maxbrc/photo-portfolio/tree/main/frontend/client/src/components): visitor pages · Home, gallery, albums, image browser, header/footer, impressum, and login screens. · `frontend/client/src/components`
- [Admin UI](https://github.com/maxbrc/photo-portfolio/blob/main/frontend/client/src/components/Admin.tsx): admin screens · Authenticated administration dashboard and resource management views. · `frontend/client/src/components/Admin.tsx`
- [Client types](https://github.com/maxbrc/photo-portfolio/tree/main/frontend/client/src/types): typescript models · Frontend request/response and view-model type definitions. · `frontend/client/src/types`
- [Browser build](https://github.com/maxbrc/photo-portfolio/blob/main/frontend/client/webpack.prod.js): webpack build · Client bundle compilation for the browser runtime. · `frontend/client/webpack.prod.js`
- [SSR server](https://github.com/maxbrc/photo-portfolio/blob/main/frontend/server/src/index.tsx): node runtime · Server-side frontend runtime entry used in production packaging. · `frontend/server/src/index.tsx`

### Runtime

Container composition and external data services.

- [Compose](https://github.com/maxbrc/photo-portfolio/blob/main/docker/docker-compose.dev.yml): docker orchestration · Defines the backend, frontend, and database containers and their wiring. · `docker/docker-compose.dev.yml`
- **MariaDB**: database service · Persistent relational store for structured application data.

## Connections

- Main → Config: loads · Initializes configuration before starting the server.
- Main → Routes: mounts · Wires the HTTP router and handlers into the backend process.
- Main → DB layer: initializes · Connects to and verifies the database layer on startup.
- Main → Auth: uses · Configures authentication and token handling.
- Main → Albums: uses · Registers album business logic.
- Main → Images: uses · Registers image business logic.
- Routes → Handlers: dispatches to · Routes requests to resource-specific handlers.
- Handlers → Albums: calls · Album endpoints delegate to album domain logic.
- Handlers → Images: calls · Image and photo endpoints delegate to media logic.
- Handlers → Auth: calls · Login, refresh, and user protection rely on auth logic.
- Handlers → DB layer: reads/writes · Admin endpoints persist structured data through the DB layer.
- Handlers → Models: marshals · Handlers exchange shared payload shapes with clients.
- Albums → DB layer: persists via · Album state and assignments are stored in MariaDB.
- Images → DB layer: persists via · Image metadata is stored in MariaDB.
- Images → Models: uses · Image operations use shared model types.
- Auth → DB layer: loads users · Authentication resolves user records from persistence.
- App → Public UI: navigates to · Main app exposes the visitor-facing pages.
- App → Admin UI: navigates to · Main app exposes the authenticated admin area.
- Public UI → Client types: uses · Public views consume typed API data and site content shapes.
- Admin UI → Client types: uses · Admin screens consume typed resources and action payloads.
- Browser build → App: builds · Produces the browser client bundle.
- SSR server → App: serves · Uses the app as the server-side frontend entry.
- Compose → Main: runs · Starts the Go backend container.
- Compose → SSR server: runs · Starts the frontend container/runtime.
- Compose → MariaDB: provides · Supplies the database service to the backend.
- DB layer → MariaDB: connects to · Database access layer talks to MariaDB.
- SSR server → Routes: API client · Frontend runtime depends on the backend API surface.
