These commits are when the Protocol Buffers files have changed: (only the last 100 relevant commits are shown)
| Commit: | 72857c4 | |
|---|---|---|
| Author: | copilot-swe-agent[bot] | |
| Committer: | GitHub | |
Fix remaining buf enum naming lint issue Co-authored-by: JMBeresford <1373954+JMBeresford@users.noreply.github.com>
| Commit: | 35354f0 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | GitHub | |
chore: service gateway refactor (#559)
| Commit: | 6420383 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: clean-up service gateway
| Commit: | f5dc84e | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
chore(service-library): migrate to sqlx (#540) This PR advances the service-layer refactor by moving `retrom-service-library` off Diesel to sqlx-oriented handlers and wiring, and adds the missing `CreateGames`, `CreatePlatforms`, `DeleteLibrary`, `DeleteMissingEntries`, `AddPlatformRootDirectory`, and `AddGameRootDirectory` RPC implementations in `LibraryService` v1. - **Proto contract updates (LibraryService v1)** - Added `CreatePlatforms` and `CreateGames` RPCs to `library-service.proto`. - Added new request/response message types: - `CreatePlatformsRequest` / `CreatePlatformsResponse` - `CreateGamesRequest` / `CreateGamesResponse` - Added full doc comments and field behavior annotations (`OUTPUT_ONLY`, `REQUIRED`) across `library-service.proto` and `models.proto`. - **sqlx migration groundwork in `retrom-service-library`** - Reworked service handler modules (`library`, `root_directory`, `platform`, `game`, `game_file`) to use sqlx query patterns (`QueryBuilder`, `query_as`) against `DbPool`. - Implemented create flows for platforms and games in the new v1 service path; server always generates UUIDv7 IDs, ignoring any client-provided `id`. - Removed legacy Diesel-centric service wiring from the library service crate. - All mutating handlers (`update_games`, `update_game_files`, `delete_games`) wrapped in transactions. - **Fully implemented previously-stubbed RPCs** - `DeleteLibrary` — deletes all non-third-party platforms in a transaction (cascades to `game_platforms`/`game_files`), then removes orphaned games. - `DeleteMissingEntries` — performs filesystem existence checks outside the transaction, then in a transaction identifies orphaned games (no surviving files) and orphaned platforms (no surviving games), and hard-deletes all three sets when `dry_run = false`. - `AddPlatformRootDirectory` — inserts into `platform_root_directories` mapping table with `on conflict do nothing`. - `AddGameRootDirectory` — inserts into `game_root_directories` mapping table with `on conflict do nothing`. - **Service wiring/runtime alignment** - Simplified `library_router` to serve the v1 `LibraryService` handler backed by sqlx pool. - Updated `main.rs` to initialize DB via `retrom_db::connect` and run migrations via `retrom_db::run_migrations`. - **Codegen row-mapping support** - Extended codegen row derive list to include `retrom.services.library.v1.Platform` and `retrom.services.library.v1.GameFile` (`sqlx::FromRow`), enabling direct `query_as` mapping for these models. Example (new RPC surface): ```proto service LibraryService { rpc GetPlatforms(GetPlatformsRequest) returns (GetPlatformsResponse); rpc CreatePlatforms(CreatePlatformsRequest) returns (CreatePlatformsResponse); rpc DeleteLibrary(DeleteLibraryRequest) returns (DeleteLibraryResponse); rpc DeleteMissingEntries(DeleteMissingEntriesRequest) returns (DeleteMissingEntriesResponse); rpc GetGames(GetGamesRequest) returns (GetGamesResponse); rpc CreateGames(CreateGamesRequest) returns (CreateGamesResponse); rpc AddPlatformRootDirectory(AddPlatformRootDirectoryRequest) returns (AddPlatformRootDirectoryResponse); rpc AddGameRootDirectory(AddGameRootDirectoryRequest) returns (AddGameRootDirectoryResponse); } ```
| Commit: | 2aaf1ca | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
chore(service-metadata): migrate to sqlx (#537)
| Commit: | 104ce3e | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
fix(service-common): migrate to versioned codegen types from service layer refactor (#536)
| Commit: | eef87c8 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: proto clean up
| Commit: | 8c0937a | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
chore(service-saves): migrate to sqlx
| Commit: | 4123b62 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore(service-emulators): migrate to sqlx
| Commit: | 7766a4b | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: fix schema
| Commit: | 7d04dd1 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: fix schema
| Commit: | 5c82200 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore(service-clients): migrate to sqlx
| Commit: | c748287 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: clean up protos
| Commit: | c472742 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: implement item 2.10 - deprecated service forwarding stubs (#513) ## Summary Implements **item 2.10** from `SERVICE_LAYER_REFACTOR.md`: deprecated service forwarding stubs for `GameService`, `PlatformService`, and `ServerService`. ## Changes ### `packages/codegen/protos/retrom/services/server-service.proto` - Added `option deprecated = true;` to each of the 3 RPC methods (`GetServerInfo`, `GetServerConfig`, `UpdateServerConfig`). The file-level and service-level deprecations were already in place; this completes the method-level annotations required by the acceptance criteria. ### `packages/service-config/src/lib.rs` - Added `ConfigServiceHandlers::with_config(config: Arc<ServerConfigManager>) -> Self` constructor to allow sharing an existing config manager instance instead of always creating a fresh one. ### `packages/grpc-service/src/server/mod.rs` - Rewrote `ServerServiceHandlers` as a true forwarding stub: - Now holds `Arc<ConfigServiceHandlers>` instead of `Arc<ServerConfigManager>`. - Each RPC method delegates to the equivalent `ConfigService` v1 method and performs trivial request/response type conversion (the underlying model types `ServerInfo`/`ServerConfig` are shared between the old and new proto namespaces). - Replaced the old `test_parse_version` unit test with a `test_get_server_info` async test that exercises the full forwarding path. ### `packages/grpc-service/src/lib.rs` - Creates a single `Arc<ConfigServiceHandlers>` backed by the function's `config_manager`. - Uses `ConfigServiceServer::from_arc(config_handlers.clone())` so both `config_service` and `server_service` share the same handler instance. ### `SERVICE_LAYER_REFACTOR.md` - Marked item 2.10 as `[x]`. ## Context `GameServiceHandlers` (games.rs) and `PlatformServiceHandlers` (platforms.rs) were already forwarding stubs from earlier work. This PR completes the trio by forwarding `ServerService` to `ConfigService`.
| Commit: | e71d955 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: implement TagsService (refactor plan item 2.8) (#508) Implements item 2.8 from `SERVICE_LAYER_REFACTOR.md`: a new `TagsService` that owns all tag domain and tag management, plus game/platform tagging, as a standalone service crate following the established per-crate router pattern. ## Migration (`2026-03-25-101000_phase1-new-standalone-tables`) - Added `created_at` and `updated_at` columns to the `tag_domains` table - Seeds the four well-known domains (`genre`, `favorites`, `franchise`, `region`) directly in the migration ## Proto (`retrom/services/tags/v1/tags-service.proto`) Previously only contained the `TagDomain` and `Tag` message stubs. Now includes: - `TagsService` with 12 RPCs across four concerns: domain management, tag management, game tagging, platform tagging - `Tag` uses a flat `int32 tag_domain_id` field (matching the DB table directly) instead of a nested `TagDomain` message - `GetGameTags` / `GetPlatformTags` operate on a single `game_id` / `platform_id` and return `repeated Tag` directly (no mapping wrapper messages) - `AddGameTags` / `DeleteGameTags` and `AddPlatformTags` / `DeletePlatformTags` replace the previous `UpdateGameTags` / `UpdatePlatformTags` RPCs; requests use `{ int32 *_id; repeated int32 tag_ids; }` shape - Full request/response message set ## Codegen - Added `services.tags.v1` module to `codegen/src/lib.rs` - Added Diesel derives (`Queryable`, `Selectable`, `Identifiable`, `Insertable`, `AsChangeset`) to both `TagDomain` and `Tag` in `build.rs` — both map directly to their respective DB tables ## New crate: `retrom-service-tags` - `TagServiceHandlers` implements all 12 RPCs against the `tag_domains`, `tags`, `game_tag_maps`, and `platform_tag_maps` tables - Uses `Tag` directly via `Tag::as_select()` with no local helper structs - `CreateTagDomains` and `CreateTags` use single bulk `INSERT` statements; `CreateTags` validates all `tag_domain_id`s upfront - `GetGameTags` / `GetPlatformTags` use a single `INNER JOIN` query against the mapping tables to return tags directly, avoiding a separate round-trip - `AddGameTags` / `AddPlatformTags` insert mapping rows in bulk with `ON CONFLICT DO NOTHING` and use `.returning(tag_id)` to return only the actually-inserted rows, without an extra transaction - `DeleteGameTags` / `DeletePlatformTags` use `.returning(tag_id)` on the delete statement to retrieve affected tag IDs, then fetch and return the full `Tag` rows - `DeleteTagDomains` rejects well-known domains with `Status::failed_precondition` - Exports `tags_router(db_pool: Arc<Pool>) -> axum::Router` per the established pattern ## Registration (`retrom-grpc-service`) - `TagsServiceServer` added to the routes builder
| Commit: | 0bb1b1f | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: extract FileExplorerService to its own crate (refactor 2.7) (#507)
| Commit: | 1fa9c4f | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(2.6): Add dedicated Job Service gRPC crate (#503)
| Commit: | 673da80 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: Updated Emulator Service — mapping-table RPCs (refactor plan 2.4) (#500)
| Commit: | b98abf0 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(metadata): implement refactor plan item 2.3 — provider-aware MetadataService v1 (#499) Implements item 2.3 of `SERVICE_LAYER_REFACTOR.md`: introduce a versioned `retrom.services.metadata.v1.MetadataService` that adds provider-awareness to the metadata layer. ### Proto - **`retrom/models/metadata.proto`** — added `optional int32 provider_id` to `UpdatedGameMetadata` (field 17) and `UpdatedPlatformMetadata` (field 9) so write operations can now carry and persist a provider FK. - **`retrom/services/metadata/v1/metadata-service.proto`** — added `MetadataService` service definition mirroring all legacy RPCs (via `retrom.*` type imports) plus the new RPC: ```protobuf rpc GetMetadataProviders(GetMetadataProvidersRequest) returns (GetMetadataProvidersResponse); ``` ### Codegen (`packages/codegen`) - Registered `services.metadata.v1.MetadataProvider` in `build.rs` `queryable_models` → Diesel derives against `metadata_providers` table. - Exposed `retrom::services::metadata::v1` module in `src/lib.rs`. ### gRPC service (`packages/grpc-service`) - `MetadataServiceHandlers` gains `#[derive(Clone)]` to allow sharing across legacy and v1 servers. - New `impl MetadataServiceV1 for MetadataServiceHandlers` — existing RPCs delegate via UFCS; `get_metadata_providers` queries the `metadata_providers` table: ```rust let providers = schema::metadata_providers::table .load::<MetadataProviderModel>(&mut conn) .await?; ``` - `MetadataServiceServerV1` wired into the Axum router alongside the legacy server (same pattern as `LibraryServiceServerV1`).
| Commit: | 3dc94f2 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(service): implement 2.2 Enhanced Library Service (#497) Implements Phase 2.2 of the service layer refactor: surface all game and platform CRUD through `retrom.services.library.v1.LibraryService`, making `GameService` and `PlatformService` redundant forwarding stubs. - **`library/v1/library-service.proto`** — promotes from model-only to a full service definition with 18 RPCs: existing library ops + Library CRUD (`GetLibraries`, `CreateLibraries`, `UpdateLibraries`) + Root Directory management (full CRUD) + platform ops + game/game-file ops. All new request/response types live in `retrom.services.library.v1`; model types imported from the existing `retrom` package. - **`game-service.proto` / `platform-service.proto`** — `option deprecated = true` at file, service, and method levels. - `build.rs` — Diesel `Queryable`/`Selectable`/`Identifiable`/`Insertable`/`AsChangeset` type attributes added for `Library` and `RootDirectory` v1 types so handlers can use them directly in queries. - `src/lib.rs` — adds `retrom::services::library::v1` via `tonic::include_proto!`. - **`library/game_handlers.rs`** / **`library/platform_handlers.rs`** *(new)* — shared free-function handler logic extracted from the top-level `games.rs` / `platforms.rs`. - **`library/library_handlers.rs`** / **`library/root_directory_handlers.rs`** *(new)* — new CRUD handlers against the `libraries` and `root_directories` tables. - **`library/mod.rs`** — `LibraryServiceHandlers` derives `Clone` and now implements *both* the legacy `retrom::LibraryService` trait and the new `retrom::services::library::v1::LibraryService` trait: ```rust impl LibraryServiceV1 for LibraryServiceHandlers { async fn get_libraries(&self, request: Request<GetLibrariesRequest>) -> ... { library_handlers::get_libraries(self.db_pool.clone(), request.into_inner()) .await.map(Response::new) } async fn get_games(&self, request: Request<GetGamesRequest>) -> ... { // converts v1 ↔ retrom package types, delegates to game_handlers } // ...all 18 RPCs } ``` - **`games.rs`** / **`platforms.rs`** — reduced to forwarding stubs; all logic now lives in `library/{game,platform}_handlers.rs`. - **`lib.rs`** — registers `LibraryServiceServerV1` alongside the existing services.
| Commit: | e1b4cc3 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(service-config): implement ConfigService to replace ServerService (refactor plan 2.1) (#496) Implements item 2.1 from the service layer refactor plan: introduces a versioned `ConfigService` under `retrom.services.config.v1` and deprecates the existing `ServerService`. - New file `retrom/services/config/v1/config-service.proto` — `ConfigService` with `GetServerInfo`, `GetServerConfig`, `UpdateServerConfig` RPCs (each with focused doc comments), reusing existing `retrom.ServerConfig` / `retrom.ServerInfo` model types - `server-service.proto` marked `option deprecated = true` at both file and service level - `ServerConfigManager` and `RetromDirs` moved from `retrom-service-common` into this crate (`src/config.rs` and `src/retrom_dirs.rs`) — `retrom-service-config` is now the sole owner of the config file on disk - `retrom-service-common` re-exports both types via `#[deprecated]` type aliases for backward compatibility — existing callers continue to compile but receive deprecation warnings guiding them to import from `retrom-service-config` directly (or use the gRPC API for config access) - `ConfigServiceHandlers` creates and owns its own `Arc<ServerConfigManager>` internally — `new()` takes no arguments - Replaces `.unwrap()` on optional request field with `tonic::Status::invalid_argument` - Exports `config_router() -> axum::Router` for per-service router composition (Phase 3); the router creates the handler (and manager) internally ```rust pub fn config_router() -> axum::Router { let config_service = ConfigServiceServer::new(ConfigServiceHandlers::new()); let mut routes_builder = tonic::service::Routes::builder(); routes_builder.add_service(config_service); routes_builder.routes().into_axum_router() } ``` - Includes `src/main.rs` and a `[[bin]]` entry in `Cargo.toml` so the service can be started as a standalone process — reads initial config for telemetry setup, initialises tracing, and serves on port 5103 - `retrom-service-config` added to the Cargo workspace and as a dependency of `retrom-grpc-service` - `ConfigServiceServer` registered in `grpc_service()` alongside the still-present `ServerServiceServer` for backward compatibility - `grpc_service()` no longer passes `config_manager` to `ConfigServiceHandlers` — the handler manages its own instance - Section 2.1: clarifies that only `ConfigService` owns `ServerConfigManager`; all other services must fetch config via gRPC - Section 3.1: updated to require all future per-service crates to include a `src/main.rs` and `[[bin]]` entry, and explicitly states they must **not** use `ServerConfigManager` directly — they must connect to the already-running `ConfigService` over gRPC
| Commit: | 38c1416 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: Phase 1 — data layer foundation for service layer refactor (#494) Implements Phase 1 of `SERVICE_LAYER_REFACTOR.md`: all DB schema additions required before the service interface redesign can begin. All changes are purely additive — no existing columns, tables, or FK relationships are removed. ## DB migrations (6, all reversible) - **`game_metadata.id`** — sequence-backed surrogate integer `id` (NOT NULL, unique); required as FK target for the new media tables - **New standalone tables** — `libraries` (with `structure_definition` path-template field), `root_directories`, `metadata_providers`, `tag_domains` (with `is_well_known` flag for seeded domains: `genre`, `favorites`, `franchise`, `region`) - **`tags`** — `(tag_domain_id, value)` unique pair; replaces the IGDB-specific `game_genres` system (data migration in Phase 4) - **Media metadata tables** — `video_metadata`, `screenshot_metadata`, `artwork_metadata` each with FK → `game_metadata.id`; normalises the deprecated `video_urls`/`screenshot_urls`/`artwork_urls` array columns - **Mapping tables** — 8 many-to-many join tables: library↔dir, platform↔dir, game↔dir, library↔platform, game↔platform, platform↔tag, game↔tag, emulator↔platform - **Existing table additions** — nullable `provider_id` + `logo_url` on `game_metadata`; `provider_id` + `icon_url` on `platform_metadata`; `default_profile_id`, `bios_directory`, `extra_files_directory` on `local_emulator_configs` ## Proto model additions (`retrom.services.*`) Three new proto files under versioned packages (Phase 2 will add service RPCs on top of these): - `retrom/services/library/v1/` — `Library`, `RootDirectory`; `structure_definition` documented with well-known tokens (`{library}`, `{platform}`, `{game}`) and arbitrary token semantics - `retrom/services/metadata/v1/` — `MetadataProvider`, `VideoMetadata`, `ScreenshotMetadata`, `ArtworkMetadata` - `retrom/services/tags/v1/` — `TagDomain` (with `is_well_known`), `Tag` Updated `retrom/models/metadata.proto` (new fields 17–19 on `GameMetadata`; fields 9–10 on `PlatformMetadata`) and `retrom/models/emulators.proto` (fields 10–12 on all three `LocalEmulatorConfig` variants). No existing field numbers touched. ## Diesel schema `schema.rs` updated with all 16 new tables and new columns; `joinable!` and `allow_tables_to_appear_in_same_query!` extended accordingly. `schema.patch` hunk headers updated to reflect the shifted line numbers.
| Commit: | 7982041 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
chore(service-library): migrate to sqlx (#540) This PR advances the service-layer refactor by moving `retrom-service-library` off Diesel to sqlx-oriented handlers and wiring, and adds the missing `CreateGames`, `CreatePlatforms`, `DeleteLibrary`, `DeleteMissingEntries`, `AddPlatformRootDirectory`, and `AddGameRootDirectory` RPC implementations in `LibraryService` v1. - **Proto contract updates (LibraryService v1)** - Added `CreatePlatforms` and `CreateGames` RPCs to `library-service.proto`. - Added new request/response message types: - `CreatePlatformsRequest` / `CreatePlatformsResponse` - `CreateGamesRequest` / `CreateGamesResponse` - Added full doc comments and field behavior annotations (`OUTPUT_ONLY`, `REQUIRED`) across `library-service.proto` and `models.proto`. - **sqlx migration groundwork in `retrom-service-library`** - Reworked service handler modules (`library`, `root_directory`, `platform`, `game`, `game_file`) to use sqlx query patterns (`QueryBuilder`, `query_as`) against `DbPool`. - Implemented create flows for platforms and games in the new v1 service path; server always generates UUIDv7 IDs, ignoring any client-provided `id`. - Removed legacy Diesel-centric service wiring from the library service crate. - All mutating handlers (`update_games`, `update_game_files`, `delete_games`) wrapped in transactions. - **Fully implemented previously-stubbed RPCs** - `DeleteLibrary` — deletes all non-third-party platforms in a transaction (cascades to `game_platforms`/`game_files`), then removes orphaned games. - `DeleteMissingEntries` — performs filesystem existence checks outside the transaction, then in a transaction identifies orphaned games (no surviving files) and orphaned platforms (no surviving games), and hard-deletes all three sets when `dry_run = false`. - `AddPlatformRootDirectory` — inserts into `platform_root_directories` mapping table with `on conflict do nothing`. - `AddGameRootDirectory` — inserts into `game_root_directories` mapping table with `on conflict do nothing`. - **Service wiring/runtime alignment** - Simplified `library_router` to serve the v1 `LibraryService` handler backed by sqlx pool. - Updated `main.rs` to initialize DB via `retrom_db::connect` and run migrations via `retrom_db::run_migrations`. - **Codegen row-mapping support** - Extended codegen row derive list to include `retrom.services.library.v1.Platform` and `retrom.services.library.v1.GameFile` (`sqlx::FromRow`), enabling direct `query_as` mapping for these models. Example (new RPC surface): ```proto service LibraryService { rpc GetPlatforms(GetPlatformsRequest) returns (GetPlatformsResponse); rpc CreatePlatforms(CreatePlatformsRequest) returns (CreatePlatformsResponse); rpc DeleteLibrary(DeleteLibraryRequest) returns (DeleteLibraryResponse); rpc DeleteMissingEntries(DeleteMissingEntriesRequest) returns (DeleteMissingEntriesResponse); rpc GetGames(GetGamesRequest) returns (GetGamesResponse); rpc CreateGames(CreateGamesRequest) returns (CreateGamesResponse); rpc AddPlatformRootDirectory(AddPlatformRootDirectoryRequest) returns (AddPlatformRootDirectoryResponse); rpc AddGameRootDirectory(AddGameRootDirectoryRequest) returns (AddGameRootDirectoryResponse); } ```
| Commit: | 7fad503 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
chore(service-metadata): migrate to sqlx (#537)
| Commit: | 720a501 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
fix(service-common): migrate to versioned codegen types from service layer refactor (#536)
| Commit: | 4e02ea8 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: proto clean up
| Commit: | 2fb6a40 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
chore(service-saves): migrate to sqlx
| Commit: | 0ed3ea8 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore(service-emulators): migrate to sqlx
| Commit: | 1211927 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: fix schema
| Commit: | 9cb05b0 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: fix schema
| Commit: | a7b06b5 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore(service-clients): migrate to sqlx
| Commit: | c0738be | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: clean up protos
| Commit: | 871b87f | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: implement item 2.10 - deprecated service forwarding stubs (#513) ## Summary Implements **item 2.10** from `SERVICE_LAYER_REFACTOR.md`: deprecated service forwarding stubs for `GameService`, `PlatformService`, and `ServerService`. ## Changes ### `packages/codegen/protos/retrom/services/server-service.proto` - Added `option deprecated = true;` to each of the 3 RPC methods (`GetServerInfo`, `GetServerConfig`, `UpdateServerConfig`). The file-level and service-level deprecations were already in place; this completes the method-level annotations required by the acceptance criteria. ### `packages/service-config/src/lib.rs` - Added `ConfigServiceHandlers::with_config(config: Arc<ServerConfigManager>) -> Self` constructor to allow sharing an existing config manager instance instead of always creating a fresh one. ### `packages/grpc-service/src/server/mod.rs` - Rewrote `ServerServiceHandlers` as a true forwarding stub: - Now holds `Arc<ConfigServiceHandlers>` instead of `Arc<ServerConfigManager>`. - Each RPC method delegates to the equivalent `ConfigService` v1 method and performs trivial request/response type conversion (the underlying model types `ServerInfo`/`ServerConfig` are shared between the old and new proto namespaces). - Replaced the old `test_parse_version` unit test with a `test_get_server_info` async test that exercises the full forwarding path. ### `packages/grpc-service/src/lib.rs` - Creates a single `Arc<ConfigServiceHandlers>` backed by the function's `config_manager`. - Uses `ConfigServiceServer::from_arc(config_handlers.clone())` so both `config_service` and `server_service` share the same handler instance. ### `SERVICE_LAYER_REFACTOR.md` - Marked item 2.10 as `[x]`. ## Context `GameServiceHandlers` (games.rs) and `PlatformServiceHandlers` (platforms.rs) were already forwarding stubs from earlier work. This PR completes the trio by forwarding `ServerService` to `ConfigService`.
| Commit: | 89abab5 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: implement TagsService (refactor plan item 2.8) (#508) Implements item 2.8 from `SERVICE_LAYER_REFACTOR.md`: a new `TagsService` that owns all tag domain and tag management, plus game/platform tagging, as a standalone service crate following the established per-crate router pattern. ## Migration (`2026-03-25-101000_phase1-new-standalone-tables`) - Added `created_at` and `updated_at` columns to the `tag_domains` table - Seeds the four well-known domains (`genre`, `favorites`, `franchise`, `region`) directly in the migration ## Proto (`retrom/services/tags/v1/tags-service.proto`) Previously only contained the `TagDomain` and `Tag` message stubs. Now includes: - `TagsService` with 12 RPCs across four concerns: domain management, tag management, game tagging, platform tagging - `Tag` uses a flat `int32 tag_domain_id` field (matching the DB table directly) instead of a nested `TagDomain` message - `GetGameTags` / `GetPlatformTags` operate on a single `game_id` / `platform_id` and return `repeated Tag` directly (no mapping wrapper messages) - `AddGameTags` / `DeleteGameTags` and `AddPlatformTags` / `DeletePlatformTags` replace the previous `UpdateGameTags` / `UpdatePlatformTags` RPCs; requests use `{ int32 *_id; repeated int32 tag_ids; }` shape - Full request/response message set ## Codegen - Added `services.tags.v1` module to `codegen/src/lib.rs` - Added Diesel derives (`Queryable`, `Selectable`, `Identifiable`, `Insertable`, `AsChangeset`) to both `TagDomain` and `Tag` in `build.rs` — both map directly to their respective DB tables ## New crate: `retrom-service-tags` - `TagServiceHandlers` implements all 12 RPCs against the `tag_domains`, `tags`, `game_tag_maps`, and `platform_tag_maps` tables - Uses `Tag` directly via `Tag::as_select()` with no local helper structs - `CreateTagDomains` and `CreateTags` use single bulk `INSERT` statements; `CreateTags` validates all `tag_domain_id`s upfront - `GetGameTags` / `GetPlatformTags` use a single `INNER JOIN` query against the mapping tables to return tags directly, avoiding a separate round-trip - `AddGameTags` / `AddPlatformTags` insert mapping rows in bulk with `ON CONFLICT DO NOTHING` and use `.returning(tag_id)` to return only the actually-inserted rows, without an extra transaction - `DeleteGameTags` / `DeletePlatformTags` use `.returning(tag_id)` on the delete statement to retrieve affected tag IDs, then fetch and return the full `Tag` rows - `DeleteTagDomains` rejects well-known domains with `Status::failed_precondition` - Exports `tags_router(db_pool: Arc<Pool>) -> axum::Router` per the established pattern ## Registration (`retrom-grpc-service`) - `TagsServiceServer` added to the routes builder
| Commit: | 4850919 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: extract FileExplorerService to its own crate (refactor 2.7) (#507)
| Commit: | a39d1a0 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(2.6): Add dedicated Job Service gRPC crate (#503)
| Commit: | 9ba40bb | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: Updated Emulator Service — mapping-table RPCs (refactor plan 2.4) (#500)
| Commit: | 8fa9283 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(metadata): implement refactor plan item 2.3 — provider-aware MetadataService v1 (#499) Implements item 2.3 of `SERVICE_LAYER_REFACTOR.md`: introduce a versioned `retrom.services.metadata.v1.MetadataService` that adds provider-awareness to the metadata layer. ### Proto - **`retrom/models/metadata.proto`** — added `optional int32 provider_id` to `UpdatedGameMetadata` (field 17) and `UpdatedPlatformMetadata` (field 9) so write operations can now carry and persist a provider FK. - **`retrom/services/metadata/v1/metadata-service.proto`** — added `MetadataService` service definition mirroring all legacy RPCs (via `retrom.*` type imports) plus the new RPC: ```protobuf rpc GetMetadataProviders(GetMetadataProvidersRequest) returns (GetMetadataProvidersResponse); ``` ### Codegen (`packages/codegen`) - Registered `services.metadata.v1.MetadataProvider` in `build.rs` `queryable_models` → Diesel derives against `metadata_providers` table. - Exposed `retrom::services::metadata::v1` module in `src/lib.rs`. ### gRPC service (`packages/grpc-service`) - `MetadataServiceHandlers` gains `#[derive(Clone)]` to allow sharing across legacy and v1 servers. - New `impl MetadataServiceV1 for MetadataServiceHandlers` — existing RPCs delegate via UFCS; `get_metadata_providers` queries the `metadata_providers` table: ```rust let providers = schema::metadata_providers::table .load::<MetadataProviderModel>(&mut conn) .await?; ``` - `MetadataServiceServerV1` wired into the Axum router alongside the legacy server (same pattern as `LibraryServiceServerV1`).
| Commit: | 1990e78 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(service): implement 2.2 Enhanced Library Service (#497) Implements Phase 2.2 of the service layer refactor: surface all game and platform CRUD through `retrom.services.library.v1.LibraryService`, making `GameService` and `PlatformService` redundant forwarding stubs. - **`library/v1/library-service.proto`** — promotes from model-only to a full service definition with 18 RPCs: existing library ops + Library CRUD (`GetLibraries`, `CreateLibraries`, `UpdateLibraries`) + Root Directory management (full CRUD) + platform ops + game/game-file ops. All new request/response types live in `retrom.services.library.v1`; model types imported from the existing `retrom` package. - **`game-service.proto` / `platform-service.proto`** — `option deprecated = true` at file, service, and method levels. - `build.rs` — Diesel `Queryable`/`Selectable`/`Identifiable`/`Insertable`/`AsChangeset` type attributes added for `Library` and `RootDirectory` v1 types so handlers can use them directly in queries. - `src/lib.rs` — adds `retrom::services::library::v1` via `tonic::include_proto!`. - **`library/game_handlers.rs`** / **`library/platform_handlers.rs`** *(new)* — shared free-function handler logic extracted from the top-level `games.rs` / `platforms.rs`. - **`library/library_handlers.rs`** / **`library/root_directory_handlers.rs`** *(new)* — new CRUD handlers against the `libraries` and `root_directories` tables. - **`library/mod.rs`** — `LibraryServiceHandlers` derives `Clone` and now implements *both* the legacy `retrom::LibraryService` trait and the new `retrom::services::library::v1::LibraryService` trait: ```rust impl LibraryServiceV1 for LibraryServiceHandlers { async fn get_libraries(&self, request: Request<GetLibrariesRequest>) -> ... { library_handlers::get_libraries(self.db_pool.clone(), request.into_inner()) .await.map(Response::new) } async fn get_games(&self, request: Request<GetGamesRequest>) -> ... { // converts v1 ↔ retrom package types, delegates to game_handlers } // ...all 18 RPCs } ``` - **`games.rs`** / **`platforms.rs`** — reduced to forwarding stubs; all logic now lives in `library/{game,platform}_handlers.rs`. - **`lib.rs`** — registers `LibraryServiceServerV1` alongside the existing services.
| Commit: | e56e3ce | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(service-config): implement ConfigService to replace ServerService (refactor plan 2.1) (#496) Implements item 2.1 from the service layer refactor plan: introduces a versioned `ConfigService` under `retrom.services.config.v1` and deprecates the existing `ServerService`. - New file `retrom/services/config/v1/config-service.proto` — `ConfigService` with `GetServerInfo`, `GetServerConfig`, `UpdateServerConfig` RPCs (each with focused doc comments), reusing existing `retrom.ServerConfig` / `retrom.ServerInfo` model types - `server-service.proto` marked `option deprecated = true` at both file and service level - `ServerConfigManager` and `RetromDirs` moved from `retrom-service-common` into this crate (`src/config.rs` and `src/retrom_dirs.rs`) — `retrom-service-config` is now the sole owner of the config file on disk - `retrom-service-common` re-exports both types via `#[deprecated]` type aliases for backward compatibility — existing callers continue to compile but receive deprecation warnings guiding them to import from `retrom-service-config` directly (or use the gRPC API for config access) - `ConfigServiceHandlers` creates and owns its own `Arc<ServerConfigManager>` internally — `new()` takes no arguments - Replaces `.unwrap()` on optional request field with `tonic::Status::invalid_argument` - Exports `config_router() -> axum::Router` for per-service router composition (Phase 3); the router creates the handler (and manager) internally ```rust pub fn config_router() -> axum::Router { let config_service = ConfigServiceServer::new(ConfigServiceHandlers::new()); let mut routes_builder = tonic::service::Routes::builder(); routes_builder.add_service(config_service); routes_builder.routes().into_axum_router() } ``` - Includes `src/main.rs` and a `[[bin]]` entry in `Cargo.toml` so the service can be started as a standalone process — reads initial config for telemetry setup, initialises tracing, and serves on port 5103 - `retrom-service-config` added to the Cargo workspace and as a dependency of `retrom-grpc-service` - `ConfigServiceServer` registered in `grpc_service()` alongside the still-present `ServerServiceServer` for backward compatibility - `grpc_service()` no longer passes `config_manager` to `ConfigServiceHandlers` — the handler manages its own instance - Section 2.1: clarifies that only `ConfigService` owns `ServerConfigManager`; all other services must fetch config via gRPC - Section 3.1: updated to require all future per-service crates to include a `src/main.rs` and `[[bin]]` entry, and explicitly states they must **not** use `ServerConfigManager` directly — they must connect to the already-running `ConfigService` over gRPC
| Commit: | f0eea84 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: Phase 1 — data layer foundation for service layer refactor (#494) Implements Phase 1 of `SERVICE_LAYER_REFACTOR.md`: all DB schema additions required before the service interface redesign can begin. All changes are purely additive — no existing columns, tables, or FK relationships are removed. ## DB migrations (6, all reversible) - **`game_metadata.id`** — sequence-backed surrogate integer `id` (NOT NULL, unique); required as FK target for the new media tables - **New standalone tables** — `libraries` (with `structure_definition` path-template field), `root_directories`, `metadata_providers`, `tag_domains` (with `is_well_known` flag for seeded domains: `genre`, `favorites`, `franchise`, `region`) - **`tags`** — `(tag_domain_id, value)` unique pair; replaces the IGDB-specific `game_genres` system (data migration in Phase 4) - **Media metadata tables** — `video_metadata`, `screenshot_metadata`, `artwork_metadata` each with FK → `game_metadata.id`; normalises the deprecated `video_urls`/`screenshot_urls`/`artwork_urls` array columns - **Mapping tables** — 8 many-to-many join tables: library↔dir, platform↔dir, game↔dir, library↔platform, game↔platform, platform↔tag, game↔tag, emulator↔platform - **Existing table additions** — nullable `provider_id` + `logo_url` on `game_metadata`; `provider_id` + `icon_url` on `platform_metadata`; `default_profile_id`, `bios_directory`, `extra_files_directory` on `local_emulator_configs` ## Proto model additions (`retrom.services.*`) Three new proto files under versioned packages (Phase 2 will add service RPCs on top of these): - `retrom/services/library/v1/` — `Library`, `RootDirectory`; `structure_definition` documented with well-known tokens (`{library}`, `{platform}`, `{game}`) and arbitrary token semantics - `retrom/services/metadata/v1/` — `MetadataProvider`, `VideoMetadata`, `ScreenshotMetadata`, `ArtworkMetadata` - `retrom/services/tags/v1/` — `TagDomain` (with `is_well_known`), `Tag` Updated `retrom/models/metadata.proto` (new fields 17–19 on `GameMetadata`; fields 9–10 on `PlatformMetadata`) and `retrom/models/emulators.proto` (fields 10–12 on all three `LocalEmulatorConfig` variants). No existing field numbers touched. ## Diesel schema `schema.rs` updated with all 16 new tables and new columns; `joinable!` and `allow_tables_to_appear_in_same_query!` extended accordingly. `schema.patch` hunk headers updated to reflect the shifted line numbers.
| Commit: | 762be0d | |
|---|---|---|
| Author: | Copilot | |
| Committer: | GitHub | |
chore(service-library): migrate to sqlx (#540) This PR advances the service-layer refactor by moving `retrom-service-library` off Diesel to sqlx-oriented handlers and wiring, and adds the missing `CreateGames`, `CreatePlatforms`, `DeleteLibrary`, `DeleteMissingEntries`, `AddPlatformRootDirectory`, and `AddGameRootDirectory` RPC implementations in `LibraryService` v1. - **Proto contract updates (LibraryService v1)** - Added `CreatePlatforms` and `CreateGames` RPCs to `library-service.proto`. - Added new request/response message types: - `CreatePlatformsRequest` / `CreatePlatformsResponse` - `CreateGamesRequest` / `CreateGamesResponse` - Added full doc comments and field behavior annotations (`OUTPUT_ONLY`, `REQUIRED`) across `library-service.proto` and `models.proto`. - **sqlx migration groundwork in `retrom-service-library`** - Reworked service handler modules (`library`, `root_directory`, `platform`, `game`, `game_file`) to use sqlx query patterns (`QueryBuilder`, `query_as`) against `DbPool`. - Implemented create flows for platforms and games in the new v1 service path; server always generates UUIDv7 IDs, ignoring any client-provided `id`. - Removed legacy Diesel-centric service wiring from the library service crate. - All mutating handlers (`update_games`, `update_game_files`, `delete_games`) wrapped in transactions. - **Fully implemented previously-stubbed RPCs** - `DeleteLibrary` — deletes all non-third-party platforms in a transaction (cascades to `game_platforms`/`game_files`), then removes orphaned games. - `DeleteMissingEntries` — performs filesystem existence checks outside the transaction, then in a transaction identifies orphaned games (no surviving files) and orphaned platforms (no surviving games), and hard-deletes all three sets when `dry_run = false`. - `AddPlatformRootDirectory` — inserts into `platform_root_directories` mapping table with `on conflict do nothing`. - `AddGameRootDirectory` — inserts into `game_root_directories` mapping table with `on conflict do nothing`. - **Service wiring/runtime alignment** - Simplified `library_router` to serve the v1 `LibraryService` handler backed by sqlx pool. - Updated `main.rs` to initialize DB via `retrom_db::connect` and run migrations via `retrom_db::run_migrations`. - **Codegen row-mapping support** - Extended codegen row derive list to include `retrom.services.library.v1.Platform` and `retrom.services.library.v1.GameFile` (`sqlx::FromRow`), enabling direct `query_as` mapping for these models. Example (new RPC surface): ```proto service LibraryService { rpc GetPlatforms(GetPlatformsRequest) returns (GetPlatformsResponse); rpc CreatePlatforms(CreatePlatformsRequest) returns (CreatePlatformsResponse); rpc DeleteLibrary(DeleteLibraryRequest) returns (DeleteLibraryResponse); rpc DeleteMissingEntries(DeleteMissingEntriesRequest) returns (DeleteMissingEntriesResponse); rpc GetGames(GetGamesRequest) returns (GetGamesResponse); rpc CreateGames(CreateGamesRequest) returns (CreateGamesResponse); rpc AddPlatformRootDirectory(AddPlatformRootDirectoryRequest) returns (AddPlatformRootDirectoryResponse); rpc AddGameRootDirectory(AddGameRootDirectoryRequest) returns (AddGameRootDirectoryResponse); } ```
| Commit: | c46f46b | |
|---|---|---|
| Author: | John Beresford | |
chore: init buf linting
| Commit: | 389fcf2 | |
|---|---|---|
| Author: | John Beresford | |
chore(service-metadata): get_similar_games RPC
| Commit: | 2531783 | |
|---|---|---|
| Author: | John Beresford | |
chore(service-library): fix up add_*_root_directory RPCs
| Commit: | 71249f4 | |
|---|---|---|
| Author: | John Beresford | |
chore(service-library): clean up
| Commit: | 8e58c9d | |
|---|---|---|
| Author: | John Beresford | |
chore(service-library): init metadata handlers
| Commit: | 27a8ae7 | |
|---|---|---|
| Author: | John Beresford | |
chore(service-metadata): rpc cleanups
| Commit: | 4269c27 | |
|---|---|---|
| Author: | John Beresford | |
chore: clean up
| Commit: | f337c39 | |
|---|---|---|
| Author: | John Beresford | |
chore(service-metadata): idiomatic rpc definitions
| Commit: | 12096dc | |
|---|---|---|
| Author: | John Beresford | |
chore: fix protos
| Commit: | dff0c13 | |
|---|---|---|
| Author: | John Beresford | |
chore(service-library): rename rpc
| Commit: | 9ef067b | |
|---|---|---|
| Author: | copilot-swe-agent[bot] | |
| Committer: | GitHub | |
Address review feedback for transactions and proto docs Co-authored-by: JMBeresford <1373954+JMBeresford@users.noreply.github.com>
| Commit: | 4327509 | |
|---|---|---|
| Author: | copilot-swe-agent[bot] | |
| Committer: | GitHub | |
fix service-library review feedback Co-authored-by: JMBeresford <1373954+JMBeresford@users.noreply.github.com>
| Commit: | 91d6a73 | |
|---|---|---|
| Author: | John Beresford | |
chore: fix proto field types
| Commit: | f458a55 | |
|---|---|---|
| Author: | copilot-swe-agent[bot] | |
| Committer: | GitHub | |
feat(service-library): add create games/platforms RPC scaffolding Co-authored-by: JMBeresford <1373954+JMBeresford@users.noreply.github.com>
| Commit: | e8c2bc3 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: fix schema
| Commit: | f08173b | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
chore(service-metadata): migrate to sqlx (#537)
| Commit: | f55da24 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
fix(service-common): migrate to versioned codegen types from service layer refactor (#536)
| Commit: | e2fa829 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: proto clean up
| Commit: | 82c4ea9 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
chore(service-saves): migrate to sqlx
| Commit: | f5917a7 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore(service-emulators): migrate to sqlx
| Commit: | 5eb6ec4 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: fix schema
| Commit: | 5847725 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore(service-clients): migrate to sqlx
| Commit: | 3007f03 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: clean up protos
| Commit: | 415bd9d | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: implement item 2.10 - deprecated service forwarding stubs (#513) ## Summary Implements **item 2.10** from `SERVICE_LAYER_REFACTOR.md`: deprecated service forwarding stubs for `GameService`, `PlatformService`, and `ServerService`. ## Changes ### `packages/codegen/protos/retrom/services/server-service.proto` - Added `option deprecated = true;` to each of the 3 RPC methods (`GetServerInfo`, `GetServerConfig`, `UpdateServerConfig`). The file-level and service-level deprecations were already in place; this completes the method-level annotations required by the acceptance criteria. ### `packages/service-config/src/lib.rs` - Added `ConfigServiceHandlers::with_config(config: Arc<ServerConfigManager>) -> Self` constructor to allow sharing an existing config manager instance instead of always creating a fresh one. ### `packages/grpc-service/src/server/mod.rs` - Rewrote `ServerServiceHandlers` as a true forwarding stub: - Now holds `Arc<ConfigServiceHandlers>` instead of `Arc<ServerConfigManager>`. - Each RPC method delegates to the equivalent `ConfigService` v1 method and performs trivial request/response type conversion (the underlying model types `ServerInfo`/`ServerConfig` are shared between the old and new proto namespaces). - Replaced the old `test_parse_version` unit test with a `test_get_server_info` async test that exercises the full forwarding path. ### `packages/grpc-service/src/lib.rs` - Creates a single `Arc<ConfigServiceHandlers>` backed by the function's `config_manager`. - Uses `ConfigServiceServer::from_arc(config_handlers.clone())` so both `config_service` and `server_service` share the same handler instance. ### `SERVICE_LAYER_REFACTOR.md` - Marked item 2.10 as `[x]`. ## Context `GameServiceHandlers` (games.rs) and `PlatformServiceHandlers` (platforms.rs) were already forwarding stubs from earlier work. This PR completes the trio by forwarding `ServerService` to `ConfigService`.
| Commit: | 44bb97d | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: implement TagsService (refactor plan item 2.8) (#508) Implements item 2.8 from `SERVICE_LAYER_REFACTOR.md`: a new `TagsService` that owns all tag domain and tag management, plus game/platform tagging, as a standalone service crate following the established per-crate router pattern. ## Migration (`2026-03-25-101000_phase1-new-standalone-tables`) - Added `created_at` and `updated_at` columns to the `tag_domains` table - Seeds the four well-known domains (`genre`, `favorites`, `franchise`, `region`) directly in the migration ## Proto (`retrom/services/tags/v1/tags-service.proto`) Previously only contained the `TagDomain` and `Tag` message stubs. Now includes: - `TagsService` with 12 RPCs across four concerns: domain management, tag management, game tagging, platform tagging - `Tag` uses a flat `int32 tag_domain_id` field (matching the DB table directly) instead of a nested `TagDomain` message - `GetGameTags` / `GetPlatformTags` operate on a single `game_id` / `platform_id` and return `repeated Tag` directly (no mapping wrapper messages) - `AddGameTags` / `DeleteGameTags` and `AddPlatformTags` / `DeletePlatformTags` replace the previous `UpdateGameTags` / `UpdatePlatformTags` RPCs; requests use `{ int32 *_id; repeated int32 tag_ids; }` shape - Full request/response message set ## Codegen - Added `services.tags.v1` module to `codegen/src/lib.rs` - Added Diesel derives (`Queryable`, `Selectable`, `Identifiable`, `Insertable`, `AsChangeset`) to both `TagDomain` and `Tag` in `build.rs` — both map directly to their respective DB tables ## New crate: `retrom-service-tags` - `TagServiceHandlers` implements all 12 RPCs against the `tag_domains`, `tags`, `game_tag_maps`, and `platform_tag_maps` tables - Uses `Tag` directly via `Tag::as_select()` with no local helper structs - `CreateTagDomains` and `CreateTags` use single bulk `INSERT` statements; `CreateTags` validates all `tag_domain_id`s upfront - `GetGameTags` / `GetPlatformTags` use a single `INNER JOIN` query against the mapping tables to return tags directly, avoiding a separate round-trip - `AddGameTags` / `AddPlatformTags` insert mapping rows in bulk with `ON CONFLICT DO NOTHING` and use `.returning(tag_id)` to return only the actually-inserted rows, without an extra transaction - `DeleteGameTags` / `DeletePlatformTags` use `.returning(tag_id)` on the delete statement to retrieve affected tag IDs, then fetch and return the full `Tag` rows - `DeleteTagDomains` rejects well-known domains with `Status::failed_precondition` - Exports `tags_router(db_pool: Arc<Pool>) -> axum::Router` per the established pattern ## Registration (`retrom-grpc-service`) - `TagsServiceServer` added to the routes builder
| Commit: | d7c0301 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: extract FileExplorerService to its own crate (refactor 2.7) (#507)
| Commit: | 6495078 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(2.6): Add dedicated Job Service gRPC crate (#503)
| Commit: | 96eeadf | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: Updated Emulator Service — mapping-table RPCs (refactor plan 2.4) (#500)
| Commit: | df59fab | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(metadata): implement refactor plan item 2.3 — provider-aware MetadataService v1 (#499) Implements item 2.3 of `SERVICE_LAYER_REFACTOR.md`: introduce a versioned `retrom.services.metadata.v1.MetadataService` that adds provider-awareness to the metadata layer. ### Proto - **`retrom/models/metadata.proto`** — added `optional int32 provider_id` to `UpdatedGameMetadata` (field 17) and `UpdatedPlatformMetadata` (field 9) so write operations can now carry and persist a provider FK. - **`retrom/services/metadata/v1/metadata-service.proto`** — added `MetadataService` service definition mirroring all legacy RPCs (via `retrom.*` type imports) plus the new RPC: ```protobuf rpc GetMetadataProviders(GetMetadataProvidersRequest) returns (GetMetadataProvidersResponse); ``` ### Codegen (`packages/codegen`) - Registered `services.metadata.v1.MetadataProvider` in `build.rs` `queryable_models` → Diesel derives against `metadata_providers` table. - Exposed `retrom::services::metadata::v1` module in `src/lib.rs`. ### gRPC service (`packages/grpc-service`) - `MetadataServiceHandlers` gains `#[derive(Clone)]` to allow sharing across legacy and v1 servers. - New `impl MetadataServiceV1 for MetadataServiceHandlers` — existing RPCs delegate via UFCS; `get_metadata_providers` queries the `metadata_providers` table: ```rust let providers = schema::metadata_providers::table .load::<MetadataProviderModel>(&mut conn) .await?; ``` - `MetadataServiceServerV1` wired into the Axum router alongside the legacy server (same pattern as `LibraryServiceServerV1`).
| Commit: | 4c4e761 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(service): implement 2.2 Enhanced Library Service (#497) Implements Phase 2.2 of the service layer refactor: surface all game and platform CRUD through `retrom.services.library.v1.LibraryService`, making `GameService` and `PlatformService` redundant forwarding stubs. ## Proto - **`library/v1/library-service.proto`** — promotes from model-only to a full service definition with 18 RPCs: existing library ops + Library CRUD (`GetLibraries`, `CreateLibraries`, `UpdateLibraries`) + Root Directory management (full CRUD) + platform ops + game/game-file ops. All new request/response types live in `retrom.services.library.v1`; model types imported from the existing `retrom` package. - **`game-service.proto` / `platform-service.proto`** — `option deprecated = true` at file, service, and method levels. ## Codegen - `build.rs` — Diesel `Queryable`/`Selectable`/`Identifiable`/`Insertable`/`AsChangeset` type attributes added for `Library` and `RootDirectory` v1 types so handlers can use them directly in queries. - `src/lib.rs` — adds `retrom::services::library::v1` via `tonic::include_proto!`. ## gRPC service - **`library/game_handlers.rs`** / **`library/platform_handlers.rs`** *(new)* — shared free-function handler logic extracted from the top-level `games.rs` / `platforms.rs`. - **`library/library_handlers.rs`** / **`library/root_directory_handlers.rs`** *(new)* — new CRUD handlers against the `libraries` and `root_directories` tables. - **`library/mod.rs`** — `LibraryServiceHandlers` derives `Clone` and now implements *both* the legacy `retrom::LibraryService` trait and the new `retrom::services::library::v1::LibraryService` trait: ```rust #[tonic::async_trait] impl LibraryServiceV1 for LibraryServiceHandlers { async fn get_libraries(&self, request: Request<GetLibrariesRequest>) -> ... { library_handlers::get_libraries(self.db_pool.clone(), request.into_inner()) .await.map(Response::new) } async fn get_games(&self, request: Request<GetGamesRequest>) -> ... { // converts v1 ↔ retrom package types, delegates to game_handlers } // ...all 18 RPCs } ``` - **`games.rs`** / **`platforms.rs`** — reduced to forwarding stubs; all logic now lives in `library/{game,platform}_handlers.rs`. - **`lib.rs`** — registers `LibraryServiceServerV1` alongside the existing services.
| Commit: | e1f59dd | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(service-config): implement ConfigService to replace ServerService (refactor plan 2.1) (#496) Implements item 2.1 from the service layer refactor plan: introduces a versioned `ConfigService` under `retrom.services.config.v1` and deprecates the existing `ServerService`. - New file `retrom/services/config/v1/config-service.proto` — `ConfigService` with `GetServerInfo`, `GetServerConfig`, `UpdateServerConfig` RPCs (each with focused doc comments), reusing existing `retrom.ServerConfig` / `retrom.ServerInfo` model types - `server-service.proto` marked `option deprecated = true` at both file and service level - `ServerConfigManager` and `RetromDirs` moved from `retrom-service-common` into this crate (`src/config.rs` and `src/retrom_dirs.rs`) — `retrom-service-config` is now the sole owner of the config file on disk - `retrom-service-common` re-exports both types via `#[deprecated]` type aliases for backward compatibility — existing callers continue to compile but receive deprecation warnings guiding them to import from `retrom-service-config` directly (or use the gRPC API for config access) - `ConfigServiceHandlers` creates and owns its own `Arc<ServerConfigManager>` internally — `new()` takes no arguments - Replaces `.unwrap()` on optional request field with `tonic::Status::invalid_argument` - Exports `config_router() -> axum::Router` for per-service router composition (Phase 3); the router creates the handler (and manager) internally ```rust pub fn config_router() -> axum::Router { let config_service = ConfigServiceServer::new(ConfigServiceHandlers::new()); let mut routes_builder = tonic::service::Routes::builder(); routes_builder.add_service(config_service); routes_builder.routes().into_axum_router() } ``` - Includes `src/main.rs` and a `[[bin]]` entry in `Cargo.toml` so the service can be started as a standalone process — reads initial config for telemetry setup, initialises tracing, and serves on port 5103 - `retrom-service-config` added to the Cargo workspace and as a dependency of `retrom-grpc-service` - `ConfigServiceServer` registered in `grpc_service()` alongside the still-present `ServerServiceServer` for backward compatibility - `grpc_service()` no longer passes `config_manager` to `ConfigServiceHandlers` — the handler manages its own instance - Section 2.1: clarifies that only `ConfigService` owns `ServerConfigManager`; all other services must fetch config via gRPC - Section 3.1: updated to require all future per-service crates to include a `src/main.rs` and `[[bin]]` entry, and explicitly states they must **not** use `ServerConfigManager` directly — they must connect to the already-running `ConfigService` over gRPC
| Commit: | c7c9815 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: Phase 1 — data layer foundation for service layer refactor (#494) Implements Phase 1 of `SERVICE_LAYER_REFACTOR.md`: all DB schema additions required before the service interface redesign can begin. All changes are purely additive — no existing columns, tables, or FK relationships are removed. ## DB migrations (6, all reversible) - **`game_metadata.id`** — sequence-backed surrogate integer `id` (NOT NULL, unique); required as FK target for the new media tables - **New standalone tables** — `libraries` (with `structure_definition` path-template field), `root_directories`, `metadata_providers`, `tag_domains` (with `is_well_known` flag for seeded domains: `genre`, `favorites`, `franchise`, `region`) - **`tags`** — `(tag_domain_id, value)` unique pair; replaces the IGDB-specific `game_genres` system (data migration in Phase 4) - **Media metadata tables** — `video_metadata`, `screenshot_metadata`, `artwork_metadata` each with FK → `game_metadata.id`; normalises the deprecated `video_urls`/`screenshot_urls`/`artwork_urls` array columns - **Mapping tables** — 8 many-to-many join tables: library↔dir, platform↔dir, game↔dir, library↔platform, game↔platform, platform↔tag, game↔tag, emulator↔platform - **Existing table additions** — nullable `provider_id` + `logo_url` on `game_metadata`; `provider_id` + `icon_url` on `platform_metadata`; `default_profile_id`, `bios_directory`, `extra_files_directory` on `local_emulator_configs` ## Proto model additions (`retrom.services.*`) Three new proto files under versioned packages (Phase 2 will add service RPCs on top of these): - `retrom/services/library/v1/` — `Library`, `RootDirectory`; `structure_definition` documented with well-known tokens (`{library}`, `{platform}`, `{game}`) and arbitrary token semantics - `retrom/services/metadata/v1/` — `MetadataProvider`, `VideoMetadata`, `ScreenshotMetadata`, `ArtworkMetadata` - `retrom/services/tags/v1/` — `TagDomain` (with `is_well_known`), `Tag` Updated `retrom/models/metadata.proto` (new fields 17–19 on `GameMetadata`; fields 9–10 on `PlatformMetadata`) and `retrom/models/emulators.proto` (fields 10–12 on all three `LocalEmulatorConfig` variants). No existing field numbers touched. ## Diesel schema `schema.rs` updated with all 16 new tables and new columns; `joinable!` and `allow_tables_to_appear_in_same_query!` extended accordingly. `schema.patch` hunk headers updated to reflect the shifted line numbers.
| Commit: | c059d2b | |
|---|---|---|
| Author: | John Beresford | |
chore: clean up
| Commit: | 9d096f2 | |
|---|---|---|
| Author: | John Beresford | |
chore: clean up
| Commit: | bd50e8d | |
|---|---|---|
| Author: | copilot-swe-agent[bot] | |
| Committer: | GitHub | |
refactor: rename LinkMetadata to GameMetadataLink, remove links field from GameMetadata proto - Rename `LinkMetadata` → `GameMetadataLink` in models.proto - Remove comment before `GameMetadataLink` message - Remove `repeated string links = 12` from `GameMetadata` proto - Remove `#[sqlx(skip)]` attribute from build.rs (no longer needed) - Update build.rs row_models entry to use `GameMetadataLink` - Remove `fetch_game_metadata_links` helper and all `links` field usages from metadata service - Remove unused `links` variable from igdb games provider - Remove `links` field assignment from steam provider Co-authored-by: JMBeresford <1373954+JMBeresford@users.noreply.github.com>
| Commit: | 3a9ae69 | |
|---|---|---|
| Author: | copilot-swe-agent[bot] | |
| Committer: | GitHub | |
feat: add LinkMetadata proto, make provider_id mandatory, use LinkMetadata in service Co-authored-by: JMBeresford <1373954+JMBeresford@users.noreply.github.com>
| Commit: | ff634c1 | |
|---|---|---|
| Author: | copilot-swe-agent[bot] | |
| Committer: | GitHub | |
fix: use #[sqlx(skip)] for GameMetadata.links to fix FromRow derive Vec<String> does not implement sqlx::Type<Sqlite>, so #[sqlx(default)] was insufficient. Switching to #[sqlx(skip)] tells sqlx to completely omit the field from row decoding and always use Default::default() instead, which resolves the compile error. Co-authored-by: JMBeresford <1373954+JMBeresford@users.noreply.github.com>
| Commit: | c5c519e | |
|---|---|---|
| Author: | Copilot | |
| Committer: | GitHub | |
fix(service-common): migrate to versioned codegen types from service layer refactor (#536)
| Commit: | dbd10d7 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore(service-metadata): re-impl media metadata handling
| Commit: | 03d6b15 | |
|---|---|---|
| Author: | John Beresford | |
chore: proto clean up
| Commit: | 4e42a52 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | GitHub | |
chore(service-saves): migrate to sqlx
| Commit: | f4b8502 | |
|---|---|---|
| Author: | John Beresford | |
chore(service-saves): clean up
| Commit: | a774bf6 | |
|---|---|---|
| Author: | copilot-swe-agent[bot] | |
| Committer: | John Beresford | |
Address PR review: lowercase SQL, build_query_scalar, ? error, UUID string IDs, add Game to row_models Co-authored-by: JMBeresford <1373954+JMBeresford@users.noreply.github.com>
| Commit: | a3ffb37 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore(service-emulators): migrate to sqlx
| Commit: | 3b7eef0 | |
|---|---|---|
| Author: | John Beresford | |
chore: fix schema
| Commit: | 7a4de57 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: fix schema
| Commit: | d5472ee | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore(service-clients): migrate to sqlx
| Commit: | a3ecf94 | |
|---|---|---|
| Author: | John Beresford | |
| Committer: | John Beresford | |
chore: clean up protos
| Commit: | ecd807e | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: implement item 2.10 - deprecated service forwarding stubs (#513) ## Summary Implements **item 2.10** from `SERVICE_LAYER_REFACTOR.md`: deprecated service forwarding stubs for `GameService`, `PlatformService`, and `ServerService`. ## Changes ### `packages/codegen/protos/retrom/services/server-service.proto` - Added `option deprecated = true;` to each of the 3 RPC methods (`GetServerInfo`, `GetServerConfig`, `UpdateServerConfig`). The file-level and service-level deprecations were already in place; this completes the method-level annotations required by the acceptance criteria. ### `packages/service-config/src/lib.rs` - Added `ConfigServiceHandlers::with_config(config: Arc<ServerConfigManager>) -> Self` constructor to allow sharing an existing config manager instance instead of always creating a fresh one. ### `packages/grpc-service/src/server/mod.rs` - Rewrote `ServerServiceHandlers` as a true forwarding stub: - Now holds `Arc<ConfigServiceHandlers>` instead of `Arc<ServerConfigManager>`. - Each RPC method delegates to the equivalent `ConfigService` v1 method and performs trivial request/response type conversion (the underlying model types `ServerInfo`/`ServerConfig` are shared between the old and new proto namespaces). - Replaced the old `test_parse_version` unit test with a `test_get_server_info` async test that exercises the full forwarding path. ### `packages/grpc-service/src/lib.rs` - Creates a single `Arc<ConfigServiceHandlers>` backed by the function's `config_manager`. - Uses `ConfigServiceServer::from_arc(config_handlers.clone())` so both `config_service` and `server_service` share the same handler instance. ### `SERVICE_LAYER_REFACTOR.md` - Marked item 2.10 as `[x]`. ## Context `GameServiceHandlers` (games.rs) and `PlatformServiceHandlers` (platforms.rs) were already forwarding stubs from earlier work. This PR completes the trio by forwarding `ServerService` to `ConfigService`.
| Commit: | e6c371a | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: implement TagsService (refactor plan item 2.8) (#508) Implements item 2.8 from `SERVICE_LAYER_REFACTOR.md`: a new `TagsService` that owns all tag domain and tag management, plus game/platform tagging, as a standalone service crate following the established per-crate router pattern. ## Migration (`2026-03-25-101000_phase1-new-standalone-tables`) - Added `created_at` and `updated_at` columns to the `tag_domains` table - Seeds the four well-known domains (`genre`, `favorites`, `franchise`, `region`) directly in the migration ## Proto (`retrom/services/tags/v1/tags-service.proto`) Previously only contained the `TagDomain` and `Tag` message stubs. Now includes: - `TagsService` with 12 RPCs across four concerns: domain management, tag management, game tagging, platform tagging - `Tag` uses a flat `int32 tag_domain_id` field (matching the DB table directly) instead of a nested `TagDomain` message - `GetGameTags` / `GetPlatformTags` operate on a single `game_id` / `platform_id` and return `repeated Tag` directly (no mapping wrapper messages) - `AddGameTags` / `DeleteGameTags` and `AddPlatformTags` / `DeletePlatformTags` replace the previous `UpdateGameTags` / `UpdatePlatformTags` RPCs; requests use `{ int32 *_id; repeated int32 tag_ids; }` shape - Full request/response message set ## Codegen - Added `services.tags.v1` module to `codegen/src/lib.rs` - Added Diesel derives (`Queryable`, `Selectable`, `Identifiable`, `Insertable`, `AsChangeset`) to both `TagDomain` and `Tag` in `build.rs` — both map directly to their respective DB tables ## New crate: `retrom-service-tags` - `TagServiceHandlers` implements all 12 RPCs against the `tag_domains`, `tags`, `game_tag_maps`, and `platform_tag_maps` tables - Uses `Tag` directly via `Tag::as_select()` with no local helper structs - `CreateTagDomains` and `CreateTags` use single bulk `INSERT` statements; `CreateTags` validates all `tag_domain_id`s upfront - `GetGameTags` / `GetPlatformTags` use a single `INNER JOIN` query against the mapping tables to return tags directly, avoiding a separate round-trip - `AddGameTags` / `AddPlatformTags` insert mapping rows in bulk with `ON CONFLICT DO NOTHING` and use `.returning(tag_id)` to return only the actually-inserted rows, without an extra transaction - `DeleteGameTags` / `DeletePlatformTags` use `.returning(tag_id)` on the delete statement to retrieve affected tag IDs, then fetch and return the full `Tag` rows - `DeleteTagDomains` rejects well-known domains with `Status::failed_precondition` - Exports `tags_router(db_pool: Arc<Pool>) -> axum::Router` per the established pattern ## Registration (`retrom-grpc-service`) - `TagsServiceServer` added to the routes builder
| Commit: | ab1758c | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: extract FileExplorerService to its own crate (refactor 2.7) (#507)
| Commit: | b87ec6b | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(2.6): Add dedicated Job Service gRPC crate (#503)
| Commit: | 3391a78 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: Updated Emulator Service — mapping-table RPCs (refactor plan 2.4) (#500)
| Commit: | 3b9228b | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(metadata): implement refactor plan item 2.3 — provider-aware MetadataService v1 (#499) Implements item 2.3 of `SERVICE_LAYER_REFACTOR.md`: introduce a versioned `retrom.services.metadata.v1.MetadataService` that adds provider-awareness to the metadata layer. ### Proto - **`retrom/models/metadata.proto`** — added `optional int32 provider_id` to `UpdatedGameMetadata` (field 17) and `UpdatedPlatformMetadata` (field 9) so write operations can now carry and persist a provider FK. - **`retrom/services/metadata/v1/metadata-service.proto`** — added `MetadataService` service definition mirroring all legacy RPCs (via `retrom.*` type imports) plus the new RPC: ```protobuf rpc GetMetadataProviders(GetMetadataProvidersRequest) returns (GetMetadataProvidersResponse); ``` ### Codegen (`packages/codegen`) - Registered `services.metadata.v1.MetadataProvider` in `build.rs` `queryable_models` → Diesel derives against `metadata_providers` table. - Exposed `retrom::services::metadata::v1` module in `src/lib.rs`. ### gRPC service (`packages/grpc-service`) - `MetadataServiceHandlers` gains `#[derive(Clone)]` to allow sharing across legacy and v1 servers. - New `impl MetadataServiceV1 for MetadataServiceHandlers` — existing RPCs delegate via UFCS; `get_metadata_providers` queries the `metadata_providers` table: ```rust let providers = schema::metadata_providers::table .load::<MetadataProviderModel>(&mut conn) .await?; ``` - `MetadataServiceServerV1` wired into the Axum router alongside the legacy server (same pattern as `LibraryServiceServerV1`).
| Commit: | 569bd2c | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(service): implement 2.2 Enhanced Library Service (#497) Implements Phase 2.2 of the service layer refactor: surface all game and platform CRUD through `retrom.services.library.v1.LibraryService`, making `GameService` and `PlatformService` redundant forwarding stubs. ## Proto - **`library/v1/library-service.proto`** — promotes from model-only to a full service definition with 18 RPCs: existing library ops + Library CRUD (`GetLibraries`, `CreateLibraries`, `UpdateLibraries`) + Root Directory management (full CRUD) + platform ops + game/game-file ops. All new request/response types live in `retrom.services.library.v1`; model types imported from the existing `retrom` package. - **`game-service.proto` / `platform-service.proto`** — `option deprecated = true` at file, service, and method levels. ## Codegen - `build.rs` — Diesel `Queryable`/`Selectable`/`Identifiable`/`Insertable`/`AsChangeset` type attributes added for `Library` and `RootDirectory` v1 types so handlers can use them directly in queries. - `src/lib.rs` — adds `retrom::services::library::v1` via `tonic::include_proto!`. ## gRPC service - **`library/game_handlers.rs`** / **`library/platform_handlers.rs`** *(new)* — shared free-function handler logic extracted from the top-level `games.rs` / `platforms.rs`. - **`library/library_handlers.rs`** / **`library/root_directory_handlers.rs`** *(new)* — new CRUD handlers against the `libraries` and `root_directories` tables. - **`library/mod.rs`** — `LibraryServiceHandlers` derives `Clone` and now implements *both* the legacy `retrom::LibraryService` trait and the new `retrom::services::library::v1::LibraryService` trait: ```rust #[tonic::async_trait] impl LibraryServiceV1 for LibraryServiceHandlers { async fn get_libraries(&self, request: Request<GetLibrariesRequest>) -> ... { library_handlers::get_libraries(self.db_pool.clone(), request.into_inner()) .await.map(Response::new) } async fn get_games(&self, request: Request<GetGamesRequest>) -> ... { // converts v1 ↔ retrom package types, delegates to game_handlers } // ...all 18 RPCs } ``` - **`games.rs`** / **`platforms.rs`** — reduced to forwarding stubs; all logic now lives in `library/{game,platform}_handlers.rs`. - **`lib.rs`** — registers `LibraryServiceServerV1` alongside the existing services.
| Commit: | 28f55a8 | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat(service-config): implement ConfigService to replace ServerService (refactor plan 2.1) (#496) Implements item 2.1 from the service layer refactor plan: introduces a versioned `ConfigService` under `retrom.services.config.v1` and deprecates the existing `ServerService`. - New file `retrom/services/config/v1/config-service.proto` — `ConfigService` with `GetServerInfo`, `GetServerConfig`, `UpdateServerConfig` RPCs (each with focused doc comments), reusing existing `retrom.ServerConfig` / `retrom.ServerInfo` model types - `server-service.proto` marked `option deprecated = true` at both file and service level - `ServerConfigManager` and `RetromDirs` moved from `retrom-service-common` into this crate (`src/config.rs` and `src/retrom_dirs.rs`) — `retrom-service-config` is now the sole owner of the config file on disk - `retrom-service-common` re-exports both types via `#[deprecated]` type aliases for backward compatibility — existing callers continue to compile but receive deprecation warnings guiding them to import from `retrom-service-config` directly (or use the gRPC API for config access) - `ConfigServiceHandlers` creates and owns its own `Arc<ServerConfigManager>` internally — `new()` takes no arguments - Replaces `.unwrap()` on optional request field with `tonic::Status::invalid_argument` - Exports `config_router() -> axum::Router` for per-service router composition (Phase 3); the router creates the handler (and manager) internally ```rust pub fn config_router() -> axum::Router { let config_service = ConfigServiceServer::new(ConfigServiceHandlers::new()); let mut routes_builder = tonic::service::Routes::builder(); routes_builder.add_service(config_service); routes_builder.routes().into_axum_router() } ``` - Includes `src/main.rs` and a `[[bin]]` entry in `Cargo.toml` so the service can be started as a standalone process — reads initial config for telemetry setup, initialises tracing, and serves on port 5103 - `retrom-service-config` added to the Cargo workspace and as a dependency of `retrom-grpc-service` - `ConfigServiceServer` registered in `grpc_service()` alongside the still-present `ServerServiceServer` for backward compatibility - `grpc_service()` no longer passes `config_manager` to `ConfigServiceHandlers` — the handler manages its own instance - Section 2.1: clarifies that only `ConfigService` owns `ServerConfigManager`; all other services must fetch config via gRPC - Section 3.1: updated to require all future per-service crates to include a `src/main.rs` and `[[bin]]` entry, and explicitly states they must **not** use `ServerConfigManager` directly — they must connect to the already-running `ConfigService` over gRPC
| Commit: | 4f8ec3b | |
|---|---|---|
| Author: | Copilot | |
| Committer: | John Beresford | |
feat: Phase 1 — data layer foundation for service layer refactor (#494) Implements Phase 1 of `SERVICE_LAYER_REFACTOR.md`: all DB schema additions required before the service interface redesign can begin. All changes are purely additive — no existing columns, tables, or FK relationships are removed. ## DB migrations (6, all reversible) - **`game_metadata.id`** — sequence-backed surrogate integer `id` (NOT NULL, unique); required as FK target for the new media tables - **New standalone tables** — `libraries` (with `structure_definition` path-template field), `root_directories`, `metadata_providers`, `tag_domains` (with `is_well_known` flag for seeded domains: `genre`, `favorites`, `franchise`, `region`) - **`tags`** — `(tag_domain_id, value)` unique pair; replaces the IGDB-specific `game_genres` system (data migration in Phase 4) - **Media metadata tables** — `video_metadata`, `screenshot_metadata`, `artwork_metadata` each with FK → `game_metadata.id`; normalises the deprecated `video_urls`/`screenshot_urls`/`artwork_urls` array columns - **Mapping tables** — 8 many-to-many join tables: library↔dir, platform↔dir, game↔dir, library↔platform, game↔platform, platform↔tag, game↔tag, emulator↔platform - **Existing table additions** — nullable `provider_id` + `logo_url` on `game_metadata`; `provider_id` + `icon_url` on `platform_metadata`; `default_profile_id`, `bios_directory`, `extra_files_directory` on `local_emulator_configs` ## Proto model additions (`retrom.services.*`) Three new proto files under versioned packages (Phase 2 will add service RPCs on top of these): - `retrom/services/library/v1/` — `Library`, `RootDirectory`; `structure_definition` documented with well-known tokens (`{library}`, `{platform}`, `{game}`) and arbitrary token semantics - `retrom/services/metadata/v1/` — `MetadataProvider`, `VideoMetadata`, `ScreenshotMetadata`, `ArtworkMetadata` - `retrom/services/tags/v1/` — `TagDomain` (with `is_well_known`), `Tag` Updated `retrom/models/metadata.proto` (new fields 17–19 on `GameMetadata`; fields 9–10 on `PlatformMetadata`) and `retrom/models/emulators.proto` (fields 10–12 on all three `LocalEmulatorConfig` variants). No existing field numbers touched. ## Diesel schema `schema.rs` updated with all 16 new tables and new columns; `joinable!` and `allow_tables_to_appear_in_same_query!` extended accordingly. `schema.patch` hunk headers updated to reflect the shifted line numbers.
| Commit: | 605f47a | |
|---|---|---|
| Author: | copilot-swe-agent[bot] | |
| Committer: | GitHub | |
feat: begin proto model ID migration from int32 to string for v2 schema compatibility Agent-Logs-Url: https://github.com/JMBeresford/retrom/sessions/3d74cd8b-6549-4e6a-96d5-f026a6c4d886 Co-authored-by: JMBeresford <1373954+JMBeresford@users.noreply.github.com>