app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 31fcb41e07985754663f42e4e80fd7f18564f286
parent 3ada037acc2c6a2cd4b0ed0f3b573a5285632be9
Author: triesap <tyson@radroots.org>
Date:   Sat,  1 Aug 2026 18:23:22 +0000

accounts: define the proof model vocabulary

- add explicit account identifiers and local login status
- constrain accounts to the approved proof fields
- model the complete typed action and problem surfaces
- establish an empty account state and add-account draft

Diffstat:
Aapp/desktop/src/main/kotlin/org/radroots/studio/accounts/model/Account.kt | 13+++++++++++++
Aapp/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountId.kt | 6++++++
Aapp/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountsAction.kt | 37+++++++++++++++++++++++++++++++++++++
Aapp/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountsProblem.kt | 22++++++++++++++++++++++
Aapp/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountsState.kt | 14++++++++++++++
Aapp/desktop/src/test/kotlin/org/radroots/studio/accounts/model/AccountsStateTest.kt | 33+++++++++++++++++++++++++++++++++
6 files changed, 125 insertions(+), 0 deletions(-)

diff --git a/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/Account.kt b/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/Account.kt @@ -0,0 +1,13 @@ +package org.radroots.studio.accounts.model + +enum class LoginStatus { + LoggedOut, + LoggedIn, +} + +data class Account( + val id: AccountId, + val displayName: String, + val serverUrl: String, + val loginStatus: LoginStatus, +) diff --git a/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountId.kt b/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountId.kt @@ -0,0 +1,6 @@ +package org.radroots.studio.accounts.model + +@JvmInline +value class AccountId( + val value: String, +) diff --git a/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountsAction.kt b/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountsAction.kt @@ -0,0 +1,37 @@ +package org.radroots.studio.accounts.model + +sealed interface AccountsAction { + data class EditAddDisplayName( + val value: String, + ) : AccountsAction + + data class EditAddServerUrl( + val value: String, + ) : AccountsAction + + data object SubmitAddAccount : AccountsAction + + data class SelectAccount( + val accountId: AccountId, + ) : AccountsAction + + data class LogIn( + val accountId: AccountId, + ) : AccountsAction + + data class LogOut( + val accountId: AccountId, + ) : AccountsAction + + data class RequestRemoveAccount( + val accountId: AccountId, + ) : AccountsAction + + data object CancelRemoveAccount : AccountsAction + + data class ConfirmRemoveAccount( + val accountId: AccountId, + ) : AccountsAction + + data object DismissProblem : AccountsAction +} diff --git a/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountsProblem.kt b/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountsProblem.kt @@ -0,0 +1,22 @@ +package org.radroots.studio.accounts.model + +sealed interface AccountsProblem { + data object BlankDisplayName : AccountsProblem + + data object InvalidServerUrl : AccountsProblem + + data object InvalidGeneratedAccountId : AccountsProblem + + data class DuplicateAccountId( + val accountId: AccountId, + ) : AccountsProblem + + data class AccountNotFound( + val accountId: AccountId, + ) : AccountsProblem + + data class RemovalTargetMismatch( + val expectedAccountId: AccountId?, + val actualAccountId: AccountId, + ) : AccountsProblem +} diff --git a/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountsState.kt b/app/desktop/src/main/kotlin/org/radroots/studio/accounts/model/AccountsState.kt @@ -0,0 +1,14 @@ +package org.radroots.studio.accounts.model + +data class AddAccountDraft( + val displayName: String = "", + val serverUrl: String = "", +) + +data class AccountsState( + val accounts: List<Account> = emptyList(), + val selectedAccountId: AccountId? = null, + val addDraft: AddAccountDraft = AddAccountDraft(), + val pendingRemovalAccountId: AccountId? = null, + val problem: AccountsProblem? = null, +) diff --git a/app/desktop/src/test/kotlin/org/radroots/studio/accounts/model/AccountsStateTest.kt b/app/desktop/src/test/kotlin/org/radroots/studio/accounts/model/AccountsStateTest.kt @@ -0,0 +1,33 @@ +package org.radroots.studio.accounts.model + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class AccountsStateTest { + @Test + fun defaultStateIsEmpty() { + val state = AccountsState() + + assertEquals(emptyList(), state.accounts) + assertNull(state.selectedAccountId) + assertEquals(AddAccountDraft(), state.addDraft) + assertNull(state.pendingRemovalAccountId) + assertNull(state.problem) + } + + @Test + fun accountContainsOnlyTheApprovedProofFields() { + val account = Account( + id = AccountId("account-1"), + displayName = "Farm Account", + serverUrl = "https://farm.example.test", + loginStatus = LoginStatus.LoggedOut, + ) + + assertEquals("account-1", account.id.value) + assertEquals("Farm Account", account.displayName) + assertEquals("https://farm.example.test", account.serverUrl) + assertEquals(LoginStatus.LoggedOut, account.loginStatus) + } +}