feat(account): SQLite Accounts repository (task 20)

Merged
MP
6mo ago
+1202-16

Summary

• Add accounts SQLite table migration with UNIQUE(service_name, username) constraint
• Refactor Account domain model: id → AccountId(String) newtype matching TEXT PRIMARY KEY spec
• Add missing fields: traffic_total, last_validated, created_at
• Sea-orm entity with from_domain/into_domain converters handling type conversions
• AccountRepository driven port with find_by_id, save, list, list_by_service, delete
• SqliteAccountRepo adapter implementing the port with proper UNIQUE violation error handling
• Credentials stored in keyring only — SQLite refs via Account::credential_ref() method
• Comprehensive test coverage: domain 99.70%, adapter 95.81%, migrations + UNIQUE constraint tests

Type

feat (new persistence layer)

Verification

  • ✅ All 1049 workspace tests pass
  • ✅ Coverage exceeds 85% threshold
  • ✅ clippy clean, fmt applied
  • ✅ Migration safety verified on existing data
  • ✅ UNIQUE constraint enforcement tested

Unblocks

Tasks #21-25, #38, #51-56, #75-76 (Accounts commands/queries/UI, hoster plugins)


Summary by cubic

Adds SQLite-backed Accounts persistence and a driven AccountRepository to implement task 20. Refactors Account to use AccountId(String), adds traffic_total, last_validated, created_at, and hardens credential refs and value validation; credentials remain in the OS keyring.

  • New Features

    • New accounts table with UNIQUE (service_name, username) and deterministic ordering by created_at (upsert preserves created_at).
    • AccountRepository port and SqliteAccountRepo adapter with find_by_id, save (upsert), list, list_by_service, delete; UNIQUE violations map to AlreadyExists.
    • sea-orm entity with from_domain/into_domain converters; i64 conversions are checked (ValidationError if above i64::MAX).
    • Domain updates: AccountId(String), new fields, and credential_ref() → percent-encoded keyring://{service}/{username} (no credentials in SQLite).
  • Migration

    • Run DB migrations to create accounts and indexes; existing data is preserved.
    • Update call sites to construct AccountId and provide created_at where needed.
    • Ensure an OS keyring is available; passwords/tokens are not stored in SQLite.

Summary by CodeRabbit

  • New Features

    • Persistent account storage with uniqueness per (service, username), service-scoped listing, and deterministic ordering.
    • Credentials referenced via the OS keychain (not stored in DB).
    • Account metadata expanded with traffic totals, validation timestamps, and creation timestamps.
  • Tests

    • Extensive tests for migrations, persistence behavior, uniqueness constraints, ordering, deletion, and data conversions.