Media Pulse centraliza dados pessoais de consumo de mídia em quatro domínios:
- música
- livros
- filmes
- séries
O backend agrega dados de provedores externos, persiste uma visão canônica local e expõe APIs HTTP principalmente read-only para exploração, resumos e páginas de detalhe.
server/: backend Kotlin + Spring Bootfrontend/: frontend Nuxt 4docs/: contratos HTTP e notas operacionaishttp-client-env/: exemplos de ambiente para clientes HTTP locais
- Stack: Kotlin 1.9 + Spring Boot 3.5
- Java: 21
- Banco principal: PostgreSQL
- Migrations: Flyway em
server/src/main/resources/db/migration - Start local:
./server/gradlew bootRun
O backend não builda mais o frontend durante o ciclo do Gradle. O empacotamento conjunto agora acontece no Dockerfile raiz, que monta uma imagem única com:
- backend Spring Boot
- frontend estático gerado pelo Nuxt
- entrega no mesmo domínio, com APIs em
/api/*e UI em/
V1__create_event_sources_table.sqlV2__create_music_schema.sqlV3__create_books_schema.sqlV4__add_slug_to_books.sqlV5__rebuild_book_reads_as_sessions.sqlV6__add_edition_information_to_book_editions.sqlV7__create_movies_schema.sqlV8__add_movie_images.sqlV9__add_slug_to_movies.sqlV10__allow_manual_movie_sources.sqlV11__create_tv_schema.sqlV12__add_tv_show_images.sqlV13__add_tv_episode_season_title.sqlV14__create_music_duplicate_review_state.sqlV15__add_movie_collections.sql
application.yml depende principalmente destas variáveis de ambiente:
SPRING_DATASOURCE_URLSPRING_DATASOURCE_USERNAMESPRING_DATASOURCE_PASSWORDSPRING_JPA_HIBERNATE_DDL_AUTO(validatepor padrão)SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE(15MB)SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE(15MB)
PIPELINE_IMPORT_ENABLEDPIPELINE_IMPORT_CRONPIPELINE_RUN_ON_STARTUPMEDIA_PULSE_FRONTEND_STATIC_PATHmedia-pulse.allowed-originvia config YAML para CORSmedia-pulse.storage.covers-pathmedia-pulse.storage.imports-path
PLEX_URLPLEX_TOKENPLEX_IMPORT_ENABLEDPLEX_IMPORT_MOVIES_ENABLEDPLEX_IMPORT_SHOWS_ENABLEDPLEX_IMPORT_PAGE_SIZE
SPOTIFY_ENABLEDSPOTIFY_API_BASE_URLSPOTIFY_ACCOUNTS_BASE_URLSPOTIFY_CLIENT_IDSPOTIFY_CLIENT_SECRETSPOTIFY_REFRESH_TOKENSPOTIFY_OAUTH_ENABLEDSPOTIFY_REDIRECT_URISPOTIFY_SCOPESSPOTIFY_IMPORT_ENABLEDSPOTIFY_IMPORT_PAGE_SIZESPOTIFY_POLL_ENABLEDSPOTIFY_POLL_CRON
HARDCOVER_ENABLEDHARDCOVER_API_BASE_URLHARDCOVER_TOKENHARDCOVER_USER_IDHARDCOVER_POLL_ENABLEDHARDCOVER_POLL_CRONHARDCOVER_POLL_PAGE_SIZE
TMDB_ENABLEDTMDB_API_BASE_URLTMDB_IMAGE_BASE_URLTMDB_TOKENTMDB_API_KEYTMDB_RATE_LIMIT_PER_SECONDTMDB_MAX_429_RETRIESTMDB_RETRY_BACKOFF_MS
MB_IMPORT_ENABLEDMB_ENRICH_BATCH_SIZEMB_ENRICH_MAX_TAGSMB_ENRICH_MIN_REQUEST_INTERVAL_MS- parâmetros
media-pulse.http.*controlam pools e timeouts para clientes remotos, locais e de imagens
GET /api/books/libraryGET /api/books/statsGET /api/books/year/{year}GET /api/books/{bookId}GET /api/books/slug/{slug}GET /api/books/authors/{authorId}GET /api/books/listGET /api/books/searchGET /api/books/summary
GET /api/music/summaryGET /api/music/recent-albumsGET /api/music/library/artistsGET /api/music/library/albumsGET /api/music/library/tracksGET /api/music/searchGET /api/music/albums/{albumId}GET /api/music/artists/{artistId}GET /api/music/tracks/{trackId}GET /api/music/tops/artistsGET /api/music/tops/albumsGET /api/music/tops/tracksGET /api/music/tops/genresGET /api/music/coverage/artistsGET /api/music/coverage/albumsGET /api/music/albums/never-playedGET /api/music/genres/trendingGET /api/music/genres/recentGET /api/music/genres/underplayedGET /api/music/genres/top-by-source
GET /api/movies/libraryGET /api/movies/recentGET /api/movies/{movieId}GET /api/movies/slug/{slug}GET /api/movies/searchGET /api/movies/summaryGET /api/movies/statsGET /api/movies/year/{year}POST /api/movies/watches
GET /api/shows/libraryGET /api/shows/recentGET /api/shows/currently-watchingGET /api/shows/{showId}GET /api/shows/slug/{slug}GET /api/shows/searchGET /api/shows/summaryGET /api/shows/statsGET /api/shows/year/{year}GET /api/shows/catalog/suggestionsPOST /api/shows/catalogPOST /api/shows/watches
POST /webhook/plexPOST /event-sources/reprocessPOST /event-sources/{id}/reprocessPOST /api/spotify/importPOST /api/spotify/extended/importPOST /api/spotify/backfill-album-tracksGET /oauth/spotify/loginGET /oauth/spotify/callbackPOST /api/plex/music/importPOST /api/musicbrainz/enrich-album-genresPOST /api/musicbrainz/enrich-album-genres/drain
O frontend em frontend/ pode ser servido separadamente para desenvolvimento ou via imagem combinada.
Para desenvolvimento local do Nuxt, use NUXT_PUBLIC_API_BASE se o backend estiver em outra origem. Em produção no mesmo domínio, o valor esperado é relativo, normalmente /api.
Se o frontend rodar em outra origem, ajuste media-pulse.allowed-origin para incluir essa origem no CORS.
O repositório agora tem três Dockerfiles com responsabilidades distintas:
frontend/Dockerfile: build e entrega standalone do frontend estático vianginxserver/Dockerfile: build e entrega standalone do backendDockerfile: imagem combinada para produção, servindo frontend e backend no mesmo domínio
Fluxo padrão de publicação:
make build VERSION=1.0.0-beta.35 EXTRA_TAGS="latest"
make push VERSION=1.0.0-beta.35 EXTRA_TAGS="latest"Por padrão, o Makefile usa o Dockerfile raiz.
docs/books-api.mddocs/music-api.mddocs/movies-api.mddocs/shows-api.mddocs/plex-movie-ingestion.mddocs/plex-show-ingestion.mddocs/operations-api.mddocs/openapi.yaml