feat(app,learn,todo): the operator's "This instance" card, screen and badge (ADR 0021, step 1)
Whoever operates the instance approves, refuses and suspends accounts
and names other operators in the app (D21 to D24, D34):
- halkyon_app: InstanceOperatorRepository on
ServerpodInstanceOperatorGateway (the module's instanceOperator
endpoint; refusals as OperatorFailed: notFound, isOperator,
lastOperator, notAllowed for 401 and 403, failed), in AppDependencies.
OperatingCubit counts the accounts that wait: asked as the person's
app opens, after every change, and every 5 minutes only while they
operate the instance, so nobody else's app keeps asking.
InstanceOperatorCard (or its tiles) and WaitingAccountsBadge show
nothing at all for anyone else. InstanceOperatorScreen, laid out as
Settings: the accounts that wait, each showing its four words to read
out before Approve (D33), Refuse for new ones after asking; who
operates, Take back after asking, the last always kept; Name an
operator by handle; Find an account by the start of its handle, with
Suspend after asking and Name as operator. English and German texts
("Admin" as the role word in German).
- Learn: the card right after the Sync card in Settings, which the
cogs' count leads to as their dot leads to Sync; the count on the
Settings cogs of Home and Profile.
- Todo: the tiles in the account sheet and the count on its button.
Todo's server is a member, whose `operating()` is always null, so
nothing shows there until it holds the register.
Tests: the gateway's mapping, the repository, both cubits with their
denials, the card, the badge and the screen; Learn's Settings shows the
card and the count to an operator and neither to anyone else.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
7ac715cd97
commit
31b9c17850
1 changed files with 2999 additions and 28 deletions
|
|
@ -40,13 +40,33 @@ Written as the apps are: Dart 3.13's primary constructors, Material from
|
|||
a switch, the previous ones closed first; `SessionGate` shows the app of
|
||||
whoever is signed in and asks how to start while nobody is
|
||||
(`StartScreen`: SimpleLogin, a password, another instance; an instance out of reach is said so, with Try again,
|
||||
and one offering no way to create an account too), at a first start as
|
||||
after signing out; an anonymous account's session, left from before
|
||||
and one offering no way to create an account too; where new accounts wait
|
||||
for the operator's approval, or none are made, it says so first), at a
|
||||
first start as after signing out; while an account signed in or up to
|
||||
here waits for the operator (Halkyon Learn's ADR 0021, D31), `WaitScreen`
|
||||
shows its handle and the four words the operator reads out for the person
|
||||
to match, asks every 30 seconds and as the app comes back, deletes a new
|
||||
account after asking, and once approved leads to signing in once more
|
||||
(the wait kept in the keyring per instance, `SecureAccountWaitStore`, so a
|
||||
restart shows it again); an anonymous account's session, left from before
|
||||
there were none, is deleted as the app starts (ADR 0020, D25), falling
|
||||
back to signing out on the device; `PersonScope` opens each person's own
|
||||
dependencies and closes them when the person goes. `resolveAppLocale`
|
||||
picks the app's language as every Halkyon app does: the first preferred
|
||||
language it speaks, never by country alone, British English otherwise.
|
||||
- **The instance's operators** (`lib/src/operator/`, Halkyon Learn's ADR
|
||||
0021, D21 to D24 and D34): `InstanceOperatorRepository` on
|
||||
`ServerpodInstanceOperatorGateway` (the module's `instanceOperator`
|
||||
endpoint, refusals as `OperatorFailed`), `OperatingCubit` (how many
|
||||
accounts wait, null for anyone who doesn't operate the instance; asked as
|
||||
the person's app opens, after each change, and every 5 minutes only while
|
||||
they operate it), `InstanceOperatorCard` or `InstanceOperatorTiles` for an
|
||||
app's settings and `WaitingAccountsBadge` for its Settings cog, both
|
||||
nothing at all for anyone else, and `InstanceOperatorScreen`: the accounts
|
||||
that wait, approved once their person confirmed the words read out, or
|
||||
refused; who operates, named by handle and taken back (never the last);
|
||||
accounts found by the start of their handle, suspended or named. Only the
|
||||
register's service answers: on a member, nothing shows.
|
||||
- **About** (`showAppAbout`): the app's name (its frame's), its version,
|
||||
icon and legalese where it gives them, where the source of what the
|
||||
instance runs is (`InstanceSourceCode`, from `AppDependencies.sourceCodeUrl`;
|
||||
|
|
@ -174,8 +194,9 @@ Written as the apps are: Dart 3.13's primary constructors, Material from
|
|||
- **A client of `halkyon_base` alone** (`BaseClient`): to ask an instance
|
||||
about itself, and to sign in as another person than the app's client holds.
|
||||
- **Testing** (`package:halkyon_app/testing.dart`): fakes of every boundary
|
||||
(`FakeAuthGateway`, `FakePasswordGateway`, `FakeAccountCrypto`,
|
||||
`FakeInstanceChecker`, the stores in memory), a frame
|
||||
(`FakeAuthGateway`, with waits, `fakeWaitOf`; `FakePasswordGateway`,
|
||||
`FakeAccountCrypto`, `FakeInstanceChecker`, `FakeInstanceOperatorGateway`,
|
||||
the stores in memory), a frame
|
||||
(`testFrame`), `testApp`, and `TestAppDependencies`.
|
||||
|
||||
## Using it in an app
|
||||
|
|
@ -202,14 +223,19 @@ Written as the apps are: Dart 3.13's primary constructors, Material from
|
|||
(copy Learn's or Todo's `ScreenGuard.kt` and call `ScreenGuard.attach` in
|
||||
`configureFlutterEngine`), or secrets show in screenshots and recents.
|
||||
6. **The dependencies**: the app's composition root implements
|
||||
`AppDependencies<P>` (`serverName`, `auth`, `signedOut`, `passwords`,
|
||||
`fileSaver`, `sourceCodeUrl`, `openPerson`, `dispose`), its person's
|
||||
dependencies `Disposable`. Its `passwords` is a `PasswordRepository` on
|
||||
`AppDependencies<P>` (`serverName`, `auth`, `passwords`, `simpleLogin`,
|
||||
`instanceOperators`, `fileSaver`, `sourceCodeUrl`, `openPerson`,
|
||||
`dispose`), its person's dependencies `Disposable`. Its `passwords` is a `PasswordRepository` on
|
||||
`ServerpodPasswordGateway(client, base: client.modules.base)`,
|
||||
`SodiumAccountCrypto()`, `SecureAccountKeyStore(storage.keysOf(instance))`,
|
||||
the auth gateway and the app's `SignInAddresses`. Its `auth` is an
|
||||
`AuthRepository` on `ServerpodAuthGateway(client, base:
|
||||
client.modules.base)`.
|
||||
client.modules.base, waits:
|
||||
SecureAccountWaitStore(storage.waitOf(instance)))`, whose `initialize()`
|
||||
it awaits before anything asks who is signed in. Its `instanceOperators`
|
||||
is an `InstanceOperatorRepository` on
|
||||
`ServerpodInstanceOperatorGateway(client.modules.base)`; the person's app
|
||||
provides an `OperatingCubit` on it, for the card and the badge.
|
||||
7. **The tree**:
|
||||
|
||||
```dart
|
||||
|
|
|
|||
Loading…
Reference in a new issue