First-use journey
Shared Wisent authentication precedes this product journey. Nothing below is reachable until the shared package has restored or established a real identity and selected organization.
Overview#
Shared Wisent authentication precedes this product journey. Nothing below is reachable until the shared package has restored or established a real identity and selected organization.
Where the journey lives#
The three steps the product contracts — service ready, mailbox exists, synchronization completes — are live state on Posture, and the same readings drive the first-run walkthrough. Each step is derived from something the core reports, so the sequence can never disagree with the service:
| step | entry evidence | completion evidence | where it appears |
|---|---|---|---|
| Service | authenticated organization selected | /v1/status answers for this organization | Posture signal strip; the failure otherwise, full width |
| Mailbox | service ready | mailbox_count > 0 | Posture decision queue row "No mailbox is configured", verb → Connect |
| Synchronize | a mailbox exists | that mailbox's last_sync_at is no longer NULL | Posture decision queue row "… has never synchronized", verb → synchronize that mailbox |
First success is a completed provider-backed synchronization cycle, not explanatory navigation and not a fabricated message. An honestly empty provider inbox completes it: the Inbox empty state says so explicitly rather than implying a failure.
Why the walkthrough never gates#
An earlier build ran the Echo WisentOnboarding journey client and gated the entire workspace on its completion (SkrzynkaRootView.swift:30-34 at 01a870d). A journey-transport failure, an invalid bundled contract, or a JourneyClient initializer throw therefore hid a perfectly healthy Skrzynka behind a wizard. Progress telemetry may not stand between an operator and a working service.
The journey it tracked is also not a set of decisions; it is a sequence. Rendering it as real state costs nothing, blocks nothing, and is correct on relaunch, after an organization switch, and on a machine where the steps were completed from the CLI — none of which client-side progress tracking got right. That is what the Posture decision queue is.
The walkthrough itself returned as a card, not a gate. It floats at the bottom of the window, so every destination stays reachable while it is on screen. Its four steps — welcome, service, mailbox, sync — come from the bundled definition Sources/SkrzynkaDesktop/Resources/skrzynka-desktop-first-use.json, whose journey version and first-success fact are checked at load, and every word on the card is that definition's own presentation copy. No step advances on a claim: each transition reads what every screen reads — /v1/status answering, mailbox_count, each mailbox's last_sync_at — so a step that declines to move is reporting that the service has not answered or that no mailbox exists yet. First success is recorded from whichever screen produced the synchronization. A definition this build cannot load or validate yields no card at all; it never yields a hidden workspace.
Progress is therefore persisted, scoped to the installation rather than to the operator, because a first run is a property of this Mac. UserDefaults holds the loopback endpoint, one installation identifier, and the attempt under a versioned namespace; the journey client reads its central definition through the environment transport keyed by SKRZYNKA_DESKTOP_STADO_INTEGRATION_TOKEN and falls back to the bundled copy. Completing the walkthrough once made it unreachable, so Service carries a First-run walkthrough control that resets the attempt through the same client and reopens the card in the window already open.
The bundled definition supplies journey_version, source_revision and the version suffix of the storage namespace. The desktop does not restate that release date in its controller. A central definition must match the bundled journey version and first-success fact; only first_mailbox_sync_completed is fixed by the application because that is the fact its mailbox state can establish.
What is asked, and what is never asked#
The application asks only what alters behavior: which loopback endpoint, which Skarbiec authority, Google authorization when Gmail OAuth is selected, whether to synchronize, the text of a reply, and the recipients, subject and text of a message a mailbox originates. The connection report measures the available Gmail paths instead of assuming a particular deployment's client works. It never collects a role, an emotion, a free-form preference, a password, an OAuth token, or payment information.
Access boundary#
This private internal app has no paid capability, price, trial, checkout, renewal, billing account, or entitlement. Shared Wisent authentication establishes identity and organization access; it is not presented as a purchase. No paywall screen is manufactured for a product with no paid capability.
Recovery#
Every row below is a state the core can report. The application names it in plain language — the meaning and the recovery its own remedy table carries for that machine code — and the compose and outbound surfaces additionally render the core's code and its verbatim sentence.
- Core offline —
SERVICE_UNREACHABLEon Posture and Service, keeping the saved endpoint, with Check service as the retry. - Skarbiec unavailable — danger, not a warning: it is the credential authority, so every sync will fail. No mailbox row is created.
- Google authorization rejected or expired — the selected Gmail profile stays selected; a fresh bounded flow is one verb away. No mailbox row or token bundle is created from the rejected flow.
- Google account mismatch —
GMAIL_OAUTH_ACCOUNT_MISMATCHis stated on the Connect inspector before the browser opens, and quoted verbatim if it happens. Both accounts stay unchanged. - Profile incomplete —
MAILBOX_PROFILE_INVALIDwith the exact field sentence; the item selection and entered non-secret settings are retained. - Item already a mailbox — the item is shown as already declared, and its verb reads Declare again and import; declaring again keeps retained messages by UID.
- IMAP failure — the mailbox keeps its row and carries the stored
last_error_code; it is a Mailboxes facet, a Posture panel and a Sync panel. Retry is always explicit, and a credential refusal offers Reconnect rather than Retry. - Empty inbox — an explicit designed state naming the INBOX-only receiving scope. An import retains every available message and its UID cursor; an honestly empty provider inbox is a real answer, not a failure.
- Uncertain reply — its own Replies facet, a standing warning quoting the product's rule, and concrete next steps. Never resent automatically, and a retry requires a new idempotency key.
- Uncertain send — an originated message the core recorded as
uncertainkeeps its own Outbound facet, a standing warning naming the mailbox whose Sent mail to check, a Posture panel and a sidebar count. Never resent automatically; the only verb composes a new message under a new key. - Relaunch — no mail state to resume: the window reads the service and shows what is true now. The first-run walkthrough resumes its own attempt, because that progress is recorded on this Mac.