Skip to content

refactor(app): split lib.rs, config.rs and cli.rs into directories - #351

Merged
InstaZDLL merged 4 commits into
mainfrom
refactor/split-app
Oct 26, 2026
Merged

InstaZDLL merged 4 commits into
mainfrom
refactor/split-app

Conversation

@InstaZDLL

@InstaZDLL InstaZDLL commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Phase A of the backend restructuring, for the three files at the top of the crate: src/lib.rs, src/config.rs and src/cli.rs. Moves only. No function was renamed, no signature or logic changed, and no public path moved: everything that resolved as waveflow_server::X, crate::config::X or crate::cli::X still does, through explicit pub use lines. No file under tests/ was touched, and main.rs and build.rs compile unchanged.

Commits

  1. git mv src/config.rs src/config/mod.rs and git mv src/cli.rs src/cli/mod.rs, alone, so git records the renames.
  2. src/lib.rs → src/app/.
  3. src/config/mod.rs → one file per settings family.
  4. src/cli/mod.rs → arguments plus one file per command family.

Old → new

src/lib.rs → src/app/ (a private module, re-exported at the root)

Item(s) Now in
pub mod declarations, crate //! doc, pub use config::Config src/lib.rs, plus pub use app::{app, initialize, shutdown_signal, ApiDoc, AppState, OPENAPI_JSON_PATH, SCALAR_PATH}
AppState, negotiation_body_limit, chunk_body_limit app/state.rs
initialize, boot, shutdown_signal app/boot.rs
app, REQUEST_ID_HEADER, CREDENTIAL_BEARING_PREFIXES, trace_path app/router.rs
OPENAPI_JSON_PATH, SCALAR_PATH, ApiDoc, SecurityAddon, BEARER_SECURITY_SCHEME, PUBLIC_OPERATIONS, clear_security_on_public_operations, annotate_scope_refusals, annotate_mutation_headers, openapi_response app/openapi.rs
the inline mod tests (5 tests) app/tests.rs

src/config.rs → src/config/

Item(s) Now in
module //! doc, Config, its Debug config/mod.rs (with the mod/pub use lines)
impl Config { fn from_env }, parse_link_roots, DEFAULT_DB_ACQUIRE_TIMEOUT_MS config/from_env.rs
impl Config { fn for_data_dir } config/for_data_dir.rs
parse_env, parse_bool_env, parse_positive_env, read_trimmed_env config/env.rs
UploadLimits, CanvasLimits, LibraryEventRetention, validate_uploads, validate_canvas config/limits.rs
PodcastSettings, RemoteArtworkSettings, parse_podcast_settings config/podcasts.rs
MetadataSettings (+ off, Debug), LyricsSettings (+ off), parse_metadata_settings, parse_lyrics_settings, parse_metadata_providers, parse_lyrics_providers config/metadata.rs
ScrobbleLimits, DEFAULT_SCROBBLE_MAX_ATTEMPTS, DEFAULT_SCROBBLE_DESTINATION, LastFmApplication (+ Debug), ScrobbleDestination, test_destinations, parse_destinations config/scrobbling.rs
SETUP_TOKEN_MIN_CHARS, parse_setup_token, normalize_public_url, parse_proxy_addresses config/access.rs
DEFAULT_PID_ALBUM/_TRACK/_ARTIST, PidSpecKind, parse_pid_spec, default_pid_spec, default_pid_specs config/pid.rs
the inline mod tests (12 tests) config/tests.rs

src/cli.rs → src/cli/

Item(s) Now in
module //! doc, execute, require_admin, read_secret_env, non_blank, validate_username cli/mod.rs
Cli, Command and every *Command / *Args cli/args.rs
key, read_instance_key, Intent, open_for_key_change, rotate_key, adopt_key, report_reading, print_inventory, sync_file, sync_directory, copy_the_pair_aside, install_new_key, report_done cli/key.rs
backup, restore cli/database.rs
add_library, library_refusal, wait_for_scan, rename_library, set_library_path, set_library_links, delete_library, list_unavailable, purge_unavailable, restore_purged, set_library_watch, set_member, set_uploads, set_canvas, remove_member cli/library.rs
create_account, set_credential, revoke_credential, create_token cli/account.rs
scrobble_provider, link_scrobble, authorize_lastfm, exchange_lastfm, unlink_scrobble, scrobble_status cli/scrobble.rs
the inline mod tests (2 tests) cli/tests.rs

Line counts

Before Lines After Lines
src/lib.rs 1,426 src/lib.rs 43
app/mod.rs 20
app/state.rs 70
app/boot.rs 234
app/router.rs 222
app/openapi.rs 625
app/tests.rs 256
src/config.rs 2,084 config/mod.rs 329
config/from_env.rs 392
config/for_data_dir.rs 165
config/env.rs 59
config/limits.rs 111
config/podcasts.rs 111
config/metadata.rs 235
config/scrobbling.rs 250
config/access.rs 53
config/pid.rs 49
config/tests.rs 409
src/cli.rs 1,679 cli/mod.rs 169
cli/args.rs 434
cli/key.rs 387
cli/database.rs 68
cli/library.rs 406
cli/account.rs 109
cli/scrobble.rs 190
cli/tests.rs 22

The largest code file is app/openapi.rs at 625 lines, most of it the #[openapi(...)] path and schema lists; the largest tests.rs is config/tests.rs at 409.

Proof that nothing was lost

  • cargo test --all-features -- --list | grep -c ': test$': 663 before, 663 after. The sorted lists differ only in the five tests that sat at the crate root: tests::X is now app::tests::X. Every config::tests::* and cli::tests::* name is unchanged.
  • The split was done by a script working on line ranges, which failed if any non-blank line of the original was left unplaced or placed twice. A second check compared trimmed lines as multisets, old file against new files. The only differences it reports are use lines, the new //! headers, the impl Config { wrappers, signatures rustfmt rewrapped because pub(super) made them longer, and the test path edits listed below.
  • cargo fmt --all --check, cargo clippy --all-targets --all-features -- -D warnings and cargo test --all-features (full suite) all pass.

What changed apart from position

  • Visibility, widened only as the split required, and never to pub. In app: negotiation_body_limit, chunk_body_limit, PUBLIC_OPERATIONS, openapi_response, CREDENTIAL_BEARING_PREFIXES and trace_path became pub(super). In config: the parsers, validators and readers that from_env.rs, for_data_dir.rs or tests.rs reach from a sibling file. In cli: the handlers execute dispatches to, backup, ExchangeLastFmArgs::TOKEN_ENV, and the 67 private fields of the *Args structs. Those fields are read from the handler files now, so they are pub(super): visible inside cli and nowhere else.
  • Test paths. Each moved test module reaches into the files it tests rather than into one flat parent. In app/tests.rs: super::PUBLIC_OPERATIONS became super::openapi::PUBLIC_OPERATIONS, super::CREDENTIAL_BEARING_PREFIXES became super::router::…, and super::api:: became crate::api::. In config/tests.rs: the imports name the child modules, and super::parse_lyrics_providers became super::metadata::parse_lyrics_providers.

Where this departs from the plan, and why

  • app is a private module. Everything in it was public at the crate root and still is, through pub use in lib.rs. Making the module private adds no second public path for phase B to keep or retire.
  • The body-limit helpers are in state.rs, not router.rs. They compute three AppState fields, the field docs describe them, and only boot calls them. The router never does.
  • shutdown_signal is in boot.rs. A file of its own would have held 26 lines.
  • OPENAPI_JSON_PATH and SCALAR_PATH are in openapi.rs. They are where the document and its reference are served. reference.rs still reads crate::SCALAR_PATH.
  • Config::from_env was not broken into per-family parsers. Extracting new functions out of its body would be a restructuring of logic, not a move. It went whole into from_env.rs (392 lines), and the test fixture for_data_dir went into a file of its own. Families that already had a parser (parse_podcast_settings, parse_metadata_settings, parse_destinations, …) took it with them. Splitting from_env itself is left for a later phase.
  • Settings families. The upload limits, the canvas limits and the library change-feed retention share limits.rs: all three bound what the server keeps on its own disk, and retention alone would be a 15-line file. Remote artwork lives with podcasts because it is defined in RFC-025 beside them. The public URL, trusted proxies and setup token share access.rs. parse_link_roots and DEFAULT_DB_ACQUIRE_TIMEOUT_MS stay with from_env, their only user apart from one test.
  • Some small files. config/pid.rs (49), config/access.rs (53), config/env.rs (59) and cli/database.rs (68) are short, but each is a family the plan named, with more than one caller. Folding any of them into from_env.rs would have mixed it with unrelated settings.
  • One tests.rs per directory. app/tests.rs mixes tests of openapi.rs and router.rs, and one of them, every_public_ticket_route_has_a_redaction_prefix, exists to tie the two tables together. config/tests.rs spans five families. Giving each test a file beside its code would have meant directories for 50-line files.

Noticed, deliberately not changed

  • CLAUDE.md and AGENTS.md say "All environment access lives in src/config.rs". It now lives in src/config/. The wording is left for phase B, as agreed.
  • Two comments state a distance that no longer holds. The doc on CREDENTIAL_BEARING_PREFIXES says the canvas route is listed "two hundred lines above" in PUBLIC_OPERATIONS, and the doc on every_public_ticket_route_has_a_redaction_prefix says "two hundred lines from a redaction list". The two lists are in different files now. Both comments were kept verbatim.
  • The cli module doc still reads "Administrative CLI used before the M4 web administration surface exists". M4 has landed.
  • canvas_body_limit falls back to usize::MAX (unwrap_or(usize::MAX) in boot). chunk_body_limit, now in state.rs, documents that a ceiling falling back to "no ceiling" is the one mistake it must never make. from_env refuses the unrepresentable value, so the branch is unreachable from the environment. A Config built by hand is not validated, though, and the two helpers disagree on principle.
  • from_env reads seven settings where zero is allowed (API token TTL, scan interval, unavailable retention, purge grace, quality parallelism, migration backups, podcast refresh) with the same var / unwrap_or_else / parse / map_err block written out each time. parse_metadata_settings and parse_lyrics_settings each define the same days closure. A shared reader in env.rs would remove both repetitions, but that is a logic change.

Summary by CodeRabbit

  • Nouvelles fonctionnalités

    • Ajout de commandes d’administration pour gérer les comptes, bibliothèques, identifiants, jetons, intégrations de scrobbling et opérations de base de données.
    • Ajout de la sauvegarde, de la restauration et de la rotation ou adoption de clés d’instance.
    • Accès à la documentation de l’API aux formats OpenAPI et référence interactive.
  • Améliorations

    • Le démarrage vérifie la compatibilité de la clé d’instance et sauvegarde la base avant les migrations.
    • Les requêtes bénéficient d’identifiants de suivi; les chemins sensibles sont masqués dans les traces.

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
…, router and openapi

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
…family

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
… command family

Signed-off-by: InstaZDLL <github.105mh@8shield.net>
@github-actions github-actions Bot added scope: server Server core (Rust) scope: api Native /api/v2 surface type: refactor Code refactoring size: xl > 500 lines labels Oct 26, 2026
@coderabbitai

coderabbitai Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 7d00fb4 and 2c690c4.

Files selected for processing: 28
  • src/app/boot.rs
  • src/app/mod.rs
  • src/app/openapi.rs
  • src/app/router.rs
  • src/app/state.rs
  • src/app/tests.rs
  • src/cli.rs
  • src/cli/account.rs
  • src/cli/args.rs
  • src/cli/database.rs
  • src/cli/key.rs
  • src/cli/library.rs
  • src/cli/mod.rs
  • src/cli/scrobble.rs
  • src/cli/tests.rs
  • src/config.rs
  • src/config/access.rs
  • src/config/env.rs
  • src/config/for_data_dir.rs
  • src/config/from_env.rs
  • src/config/limits.rs
  • src/config/metadata.rs
  • src/config/mod.rs
  • src/config/pid.rs
  • src/config/podcasts.rs
  • src/config/scrobbling.rs
  • src/config/tests.rs
  • src/lib.rs
Files with no reviewable changes: 2
  • src/config.rs
  • src/cli.rs

Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Walkthrough

La configuration, l’initialisation et le routage de l’application sont désormais organisés en modules. Le changement ajoute aussi des commandes administratives pour gérer les comptes, les bibliothèques, le scrobbling, les sauvegardes et les clés.

Changes: Configuration et démarrage

Layer / File(s) Summary
Contrats et chargement de la configuration
src/config/*, src/config.rs
La configuration monolithique est remplacée par des modules de types, de parsing et de validation. Les paramètres couvrent notamment les limites, les intégrations et les variables d’environnement.
État et initialisation de l’application
src/app/boot.rs, src/app/state.rs, src/app/mod.rs, src/lib.rs
initialize ouvre la base et lance le démarrage. Celui-ci applique les migrations, prépare les services et construit AppState. shutdown_signal attend les signaux de terminaison décrits. Les éléments applicatifs sont réexportés depuis app.

Routage HTTP

Layer / File(s) Summary
Routage et documentation OpenAPI
src/app/router.rs, src/app/openapi.rs, src/app/tests.rs
Le routeur configure les identifiants de requête, les traces, la compression, les délais et CORS. Les chemins sensibles sont expurgés dans les traces. Le document OpenAPI décrit les routes, la sécurité et les réponses des mutations; les tests vérifient ces annotations.

Commandes administratives

Layer / File(s) Summary
Interface et dispatch des commandes
src/cli/args.rs, src/cli/mod.rs, src/cli.rs
L’interface CLI et son répartiteur sont déplacés dans des modules dédiés. Ils déclarent les commandes et arguments, puis dirigent les commandes vers leurs gestionnaires.
Comptes, bibliothèques et scrobbling
src/cli/account.rs, src/cli/library.rs, src/cli/scrobble.rs, src/cli/tests.rs
Les gestionnaires ajoutent les opérations de comptes, d’identifiants et de jetons, de bibliothèques et de scrobbling. Ils appliquent les contrôles d’accès et validations décrits par les commandes.
Base de données et clés
src/cli/database.rs, src/cli/key.rs
Les commandes ajoutent la sauvegarde et la restauration de la base avec sa clé. key rotate et key adopt présentent un inventaire et, après confirmation, sauvegardent la paire avant de modifier la clé et les données associées.

Priority: Low

Estimated code review effort: 5 (Critical) | ~120 minutes

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant initialize
  participant Database
  participant boot
  participant AppState
  initialize->>Database: ouvre la base
  initialize->>boot: démarre l’application
  boot->>Database: sauvegarde et applique les migrations
  boot->>AppState: construit l’état avec les services configurés
Loading
Merge Risk: Minimal · up to 2c690

This change reorganizes configuration, application startup, routing and CLI code into smaller modules without intended behavior changes. No concrete regression was found, so it looks safe to merge after the normal CI checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 48.08% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 104 functions across 26 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed Le titre décrit clairement la restructuration principale : séparation de lib.rs, config.rs et cli.rs en répertoires.
Description check Passed La description explique les objectifs, les changements, les tests exécutés, les écarts au plan et les points connus. Elle ne reprend pas les rubriques exactes du modèle, les cases du plan de test ni l…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

La description explique les objectifs, les changements, les tests exécutés, les écarts au plan et les points connus. Elle ne reprend pas les rubriques exactes du modèle, les cases du plan de test ni la confirmation AGPL-3.0-only et DCO, mais le contenu requis est globalement présent.

Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added type: refactor Code refactoring and removed type: refactor Code refactoring labels Oct 26, 2026
@InstaZDLL InstaZDLL self-assigned this Oct 26, 2026
@github-actions github-actions Bot added type: refactor Code refactoring and removed type: refactor Code refactoring labels Oct 26, 2026
Comment thread src/cli/account.rs Dismissed
Comment thread src/cli/account.rs Dismissed
Comment thread src/cli/account.rs Dismissed
Comment thread src/cli/account.rs Dismissed
Comment thread src/cli/account.rs Dismissed
Comment thread src/cli/scrobble.rs Dismissed
Comment thread src/cli/scrobble.rs Dismissed
Comment thread src/cli/scrobble.rs Dismissed
Comment thread src/cli/scrobble.rs Dismissed
Comment thread src/cli/scrobble.rs Dismissed
@InstaZDLL
InstaZDLL merged commit ff247b2 into main Oct 26, 2026
18 checks passed
@InstaZDLL
InstaZDLL deleted the refactor/split-app branch October 26, 2026 14:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: api Native /api/v2 surface scope: server Server core (Rust) size: xl > 500 lines type: refactor Code refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants