ICN Mobile Member UX Spec v1
Status: Draft
Date: 2026-03-18
Author: Matt Faherty
Anchored to: ICN repo at commit 72a8b7a3 (post feat/demo-federation-system merge)
Purpose: Build-facing spec for the ICN mobile member layer, anchored to real crates, gateway endpoints, and October 2026 demo flows.
Governing sentence: ICN mobile is a member-centered semantic layer that projects real protocol objects into a portable, scope-aware participation experience across many cooperative and community contexts.
Cross-references (convergence verified 2026-03-18):
CLAUDE.md— project status, identity, ICN framing rules ("Digital Public Infrastructure" / "Coordination OS")BOOT.md— current priorities (Coordination OS Phase 1, ICN integration, homelab hardening)TASKS.md— governance demo passed end-to-end Mar 17 (19 steps, exit 0); Phase 2 not startedicn-crate-reference.md— 38 crates, gateway endpoints, React Native SDK componentsicn-ecosystem-map.md— 5 front-end surfaces + demo UI; pilot-ui NOT wired to real icnd yeticn-forward-plan.md— Phase 2 timeline (Mar 17–Apr 17); Track D = real demo callsicn-vertical-slice-assessment.md— 70+ endpoints, zero stubs; auth flow documentedicn-status-march-2026.md— Phase 0+1 complete, ~75% overalldocs/strategy/ICN-Gap-Analysis-March-2026.md(IN REPO) — subsystem-by-subsystem reality check; only governance flow proven end-to-end; federation settlement undefined; Mana descopeddocs/strategy/ICN-Sprint-March17.md(IN REPO) — 2-week sprint (Mar 17-30) implementing forward plan at 70% capacitydocs/strategy/ICN-Roadmap-Live.md(IN REPO) — grounded 90-day roadmap; NOW/NEXT/LATER tracksdocs/strategy/ADR-001-What-ICN-Is.md(IN REPO) — Meaning Firewall formal definition; kernel/app boundarydocs/mobile/(IN REPO) — 5 historical mobile docs from Dec 2024; SUPERSEDED by this spec
1. Member Shell
The app is organized around a persistent member, not an organization.
A member is a person who:
- holds a self-sovereign identity on their device (Ed25519 keys,
did:icn:<base58pubkey>) - belongs to zero or more cooperatives, communities, and federations simultaneously
- acts under different roles and charters depending on active scope
- carries their identity, local state, and signing authority across the network
The device is the member's:
- Identity anchor — keys stored locally under age encryption (
.ICN_DATA_DIR/identity/keypair.age) - Signing agent — all actions signed locally before network submission
- Local cache — recent state cached for offline operation
- Participation surface — where the member sees what they can do and acts on it
- Continuity layer — preserves member identity and context across scope transitions
What follows the member across the network (portable)
- Core identity (DID, keys, device metadata)
- Membership list (all entities the member belongs to)
- Personal participation history (cross-scope activity view)
- Recovery state (backup phrases, recovery contacts)
- Notification preferences
- Saved filters and views
- Cross-scope action queue (Home)
What stays scoped to an entity
- Charter rules and governance configuration
- Role powers and permissions
- Local obligations and their states
- Local positions (per-unit resource state)
- Local trust relationships (per-dimension, per-scope)
- Scope-specific activity records
- Scope-specific governance context
Onboarding flow (member-first, not org-first)
- Establish or import identity on device (
icnctl id createequivalent) - Secure device (biometric unlock for signing, recovery setup)
- Enroll into one or more memberships (via invite, QR, or manual)
- Sync accessible scopes
- Land on member Home (cross-scope action queue), not an org dashboard
2. Navigation Contract
Five tabs. Mobile bottom nav. No more.
| Tab | Job | Contains | Does NOT contain |
|---|---|---|---|
| Home | What needs me now, across all memberships | Cross-scope action queue, aggregated by urgency and scope | Dashboards, metrics, vanity stats |
| Groups | My memberships and scopes | Entity cards (coop, community, federation), role indicators, charter badges, scope switcher | Org-centric "home pages" |
| Participate | What I can do in the active scope | Proposals, obligations, flow-relevant actions, unified under one surface | Separate "Governance" / "Work" / "Exchange" tabs |
| Activity | What happened, with proof | Proof-backed event stream, filterable by scope and type | Infinite social feeds, algorithmic ranking, engagement tricks |
| Profile | Who I am, across the network | Identity, devices, recovery, trust inspection, member-level settings | Org-specific settings (those live in Groups) |
Rules
- Participate is the core working surface. It reunifies governance + obligations + flows into one participation experience. The kernel separates these concerns architecturally; the UX reunifies them for the member.
- Home aggregates across memberships. A member should not have to visit each coop separately to discover pending actions.
- Groups is the scope/membership manager. Switching scope here changes the context for Participate and Activity.
- Activity is not notifications. It is the human-readable view into proof-backed events, status changes, dispute states, and cross-scope changes.
- Profile includes the honest state of device management (v1 limitations included).
3. Gateway-to-View Projection Map
Every mobile view renders projections of real ICN types. Cards are rendering primitives, not data ontologies.
3.1 Proposal → Action Card (Home + Participate)
Source: GET /v1/gov/proposals/{id} + GET /v1/gov/proposals/{id}/tally
| Card field | Source field | Notes |
|---|---|---|
| Title | proposal.title |
|
| Type badge | proposal.payload_type |
text, budget, membership, config_change |
| Scope chip | proposal.domain_id → entity lookup |
Shows entity name + type icon |
| Status | proposal.status |
Draft, Open, Accepted, Rejected, NoQuorum |
| Summary | proposal.description (truncated) |
First 2-3 sentences |
| Impact line | Derived from payload type | Budget: "Allocate X units to Y". Membership: "Add/remove Z". Config: "Change K to V" |
| Threshold info | From governance domain | "Requires 2/3 approval, 5 of 7 quorum" (charter-derived) |
| Deadline | proposal.voting_period_days + created timestamp |
"Closes in 3 days" |
| Primary action | Based on status + member role | Vote (if Open + eligible), Review (if Draft + author), View Result (if closed) |
| Proof affordance | Link to /v1/gov/proposals/{id}/proof |
"View proof" button on closed proposals |
Appears in: Home (if vote needed), Participate (always in active scope)
3.2 Obligation → Action Card (Home + Participate)
Source: Obligation state machine (issue #1306 — Issued → Accepted → Settled → Defaulted → Disputed)
| Card field | Source field | Notes |
|---|---|---|
| Title | Obligation summary | Derived from originating proposal/allocation |
| Type badge | obligation |
|
| Scope chip | Entity context | |
| Status | Obligation state | Color-coded: Issued (blue), Accepted (green), Disputed (red) |
| Provenance link | ProvenanceRef on originating JournalEntry |
"Authorized by Proposal #X" |
| Primary action | Based on state | Accept (if Issued to me), Confirm Settlement (if Accepted), Dispute (if concerned) |
Appears in: Home (if action needed), Participate (in active scope)
3.3 GovernanceProof → Detail Panel (Participate + Activity)
Source: GET /v1/gov/proposals/{id}/proof
Renders the provenance chain for a closed proposal:
- Decision hash
- Voter attestations (each signed with Ed25519)
- Verification status (the gateway verifies proofs before serving them — invalid proofs return 404)
- Link to related ExecutionReceipt if one exists
Appears in: Participate (detail view on closed proposals), Activity (as proof-backed event)
3.4 ExecutionReceipt → Provenance Link (Participate + Activity)
Source: icnctl audit receipt-chain equivalent via gateway
Shows the chain: Proposal → GovernanceProof → AllocationReceipt → ExecutionReceipt
Appears in: Detail views on obligations and allocations, Activity stream
3.5 Trust Dimensions → Trust Panel (Profile + Groups)
Source: icn-trust crate — three independent graphs
| Dimension | Scoring | Member-facing label |
|---|---|---|
| Social | 60% direct + 40% transitive | "Known through" |
| Economic | 80% direct + 20% transitive | "Relied on for" |
| Technical | Configurable | "Operates" |
Each dimension displays:
- Trust class:
isolated/known/partner/federated - Evidence basis (endorsements, history, attestations)
- Scope context (trusted in which entity)
Never collapse into a single score. "Trusted economically but unknown socially" is meaningful information.
Appears in: Profile (own trust standing), Groups (trust context for entities), Participate (trust badges on counterparties)
3.6 Entity → Membership Card (Groups)
Source: GET /v1/coops/{id} + entity model (entity:icn:<type>:<identifier>)
| Card field | Source field | Notes |
|---|---|---|
| Name | entity.name |
|
| Type | entity.type |
cooperative, community, federation |
| Role | Member's role in this entity | member, steward, delegate |
| Charter badge | Charter type if known | "Worker Coop", "Community Land Trust", etc |
| Pending actions | Count of open items in this scope | "3 votes pending" |
| Switch action | Tap to set as active scope | Updates Participate + Activity context |
Appears in: Groups
3.7 Activity Event → Event Card (Activity)
Source: Gateway WebSocket event stream + cached activity records
| Card field | Source | Notes |
|---|---|---|
| Event type | Enum | proposal_created, vote_cast, obligation_issued, settlement_confirmed, etc |
| Summary | Human-readable description | "Proposal 'Roof Repair' accepted (5 for, 1 against)" |
| Scope | Entity context | |
| Timestamp | Event timestamp | |
| Proof link | If proof-backed event | "View proof" |
| Status indicators | Sync state | local_pending, synced, confirmed, disputed |
Appears in: Activity (primary), Home (important recent events)
4. Vocabulary Contract
The ICN codebase enforces regulatory-safe language via CI linter (issue #1312). The mobile UX must match.
Required substitutions
| Never use | Always use | Why |
|---|---|---|
| payment | settlement | ICN does not route payments |
| currency | unit | ICN tracks units of account, not currencies |
| balance | position | ICN does not hold balances |
| transaction | flow record / activity record | Not financial transactions |
| wallet | identity / device | Not a financial wallet |
| debt | obligation | Obligations have lifecycle states, not debt semantics |
| transfer | resource movement / settlement | Not money transfer |
| account | position record | Not a financial account |
| ledger | activity record / flow history | Avoid "ledger" in member-facing UX |
| execution receipt | action verification / completion record | Codebase type is ExecutionReceipt; member-facing label should be human-readable |
| allocation receipt | authorization record | Codebase type is AllocationReceipt; member sees "authorized by [proposal]" |
| governance proof | decision proof / verification | Codebase type is GovernanceProof; member sees "verified decision" |
Seven Invariants (must be reflected in UX behavior)
- User-signed transitions only — no action happens without the member's cryptographic signature
- No hosted balances — positions are computed views, not custodial holdings
- No operator routing of value — the network does not move resources; members do
- Derived views are not authoritative — the proof chain is authoritative; summaries are convenience
- No embedded convertibility — units are not automatically exchangeable
- Matching/market features are opt-in — and governance-authorized
- Execution receipts close the governance loop — every resource action traces back to a governance decision
UX copy principles
- Use "position" not "balance" in summary views
- Use "flow history" not "transaction history"
- Use "activity record" not "ledger entry"
- Use "settlement" not "payment" when describing resource movement
- Use "obligation" not "debt" for tracked commitments
- When showing provenance: "Authorized by [proposal name]" not "Created by [system]"
- When showing sync state: "Saved on your device" → "Sent to network" → "Confirmed by network"
- When showing trust: "Known through [evidence]" not "Trust score: 82"
5. Provenance Rendering Contract
The actual provenance chain in the codebase:
Proposal
→ GovernanceProof (blake3 hash, voter attestations, Ed25519 signatures)
→ AllocationReceipt (links governance decision to resource allocation)
→ ExecutionReceipt (PR #1327, Invariant 7 enforcement)
→ Obligation state change (Issued → Accepted → Settled)
→ JournalEntry (Merkle-DAG linked, required ProvenanceRef)
How this renders on mobile
Every important object should expose a "Why this exists" affordance.
On a Proposal detail view:
- What this changes — derived from payload type
- Who authorized — governance domain + quorum rules
- Current proof — link to GovernanceProof (if closed)
- What followed — link to any AllocationReceipt or ExecutionReceipt
On an Obligation card:
- Authorized by — link to originating Proposal
- Proof — link to GovernanceProof that authorized it
- Execution — link to ExecutionReceipt if settled
On an Activity event:
- Source — what governance decision or obligation triggered this
- Proof — cryptographic proof reference (if proof-backed)
- Chain position — where in the Merkle-DAG this sits
Receipt verification happens on device
Per ICN-Scenarios.md (Scenario 6), receipt verification works locally on the member's device via the React Native SDK. The member does NOT need to contact the issuing organization's daemon to verify a receipt. This is a critical security and offline property — verification is self-contained once the receipt data is cached.
Progressive disclosure pattern
- Card view: One-line provenance summary ("Authorized by Proposal: Roof Repair")
- Tap to expand: Full provenance chain with links to each step
- Deep inspection: Raw proof data, hashes, attestation signatures
CLI audit equivalents on mobile
| CLI command | Mobile equivalent |
|---|---|
icnctl audit receipt-chain --receipt <hash> |
Tap "View full chain" on any proof-backed object |
icnctl audit allocation-receipt --hash <hash> |
Tap allocation link in provenance chain |
icnctl audit settlement-intent --hash <hash> |
Tap settlement link in provenance chain |
6. Scope + Role Switching Spec
The scope model
A member's active context is defined by:
ActiveContext:
entity_id: EntityId # entity:icn:<type>:<identifier>
entity_type: EntityType # cooperative | community | federation
role: MemberRole # member | steward | delegate | (charter-defined)
charter: CharterRef # which governance rules apply
permissions: Vec<Scope> # governance:read, governance:write, coop:write, etc
Switching behavior
When scope changes:
- Participate reloads with the new entity's proposals, obligations, and flow records
- Activity filters to the new scope (with option to view cross-scope)
- Available actions change based on role + charter + permissions
- Vocabulary may change (charter-specific terminology)
- Threshold displays change (different charters have different quorum/approval rules)
Scope switcher UI
Persistent element accessible from any tab (likely top bar or Groups tab):
[Scope indicator: Entity name + Role badge]
↓ tap to open
[Membership list]
- Rochester Food Coop (Steward) [worker-coop charter]
- Harbor Homes (Member) [community-land charter]
- Finger Lakes CDN (Delegate) [federation charter]
- Self (no active entity scope)
Entity type indicators
| Entity type | Icon concept | Scoping behavior |
|---|---|---|
| Cooperative | Economic/production symbol | Shows obligations, positions, patronage |
| Community | Civic/solidarity symbol | Shows governance, mutual aid, shared resources |
| Federation | Network/bridge symbol | Shows cross-entity coordination, federation proposals |
Cooperatives and Communities are co-equal
The scope switcher must NOT present these as a hierarchy:
- ❌ Individual → Cooperative → Community → Federation (ladder)
- ✅ Individual can belong to cooperatives, communities, and federations independently
A person can be a steward in a cooperative and a member of a community simultaneously. These are parallel memberships, not nested containers.
7. Charter-Adaptive Rendering Rules
When the active scope changes, the charter determines what the member sees and can do.
What the charter controls (from icn-governance crate)
# Example: contracts/templates/worker-coop.yaml
[membership]
admission = "application_plus_vote"
quorum = "two_thirds"
voting_method = "consent"
[treasury]
allocation_method = "governance_vote"
patronage_distribution = "ny_corp_law_93"
reserve_requirement = 0.10
[governance]
proposal_types = ["budget", "membership", "policy", "dissolution"]
decision_method = "consensus"
fallback = "simple_majority"
receipt_required = true
What changes in the UI per charter
| UI element | Charter field | Example variation |
|---|---|---|
| Available proposal types | governance.proposal_types |
Worker coop shows budget+membership+policy+dissolution. Event planning coop might only show budget+policy |
| Voting interface | membership.voting_method |
Consent: approve/object/stand-aside. Simple majority: for/against/abstain. Consensus: support/block |
| Threshold displays | membership.quorum + governance.decision_method |
"Requires consensus (fallback: simple majority)" vs "Requires 2/3 approval" |
| Membership flow | membership.admission |
Application+vote vs invitation vs open enrollment |
| Economic context | treasury.* |
Patronage tracking visible for worker coops. Reserve requirements shown where configured |
| Receipt requirement | governance.receipt_required |
If true, every allocation shows execution receipt status |
Rendering strategy
The mobile app does NOT hardcode governance semantics. It reads charter configuration and adapts:
- Proposal creation — only shows proposal types enabled by the charter
- Voting UI — renders the correct voting method controls
- Threshold display — computes and shows the rules from charter config
- Role labels — uses charter-appropriate terminology
- Action availability — only offers actions the member's role permits under this charter
Charter fallback
Charter templates are deployed as of Phase 1 complete (2026-03-18). Five templates exist at contracts/templates/ (worker-coop, consumer-coop, housing-coop, community-org, federation). The ratification flow (ProposalPayload::Charter, PRs #1336+#1337) is merged. If a cooperative has not yet ratified a charter, the app falls back to a default governance profile:
- Simple majority voting
- Standard proposal types (text, budget, membership, config_change)
- No patronage tracking
- No charter badge on scope switcher
8. Demo-Flow Mapping
The four October 2026 demo flows map to specific mobile screens and transitions.
Dependency: This mapping is designed against the gateway API endpoints (which exist with real handler logic — 70+ endpoints, zero stubs per the vertical slice assessment). However, the demo scripts currently run simulated responses, not real gateway calls. Phase 2 Track D converts them to real icnctl/gateway calls. The governance demo (Flow 1) was validated end-to-end via CLI on March 17 (19 steps, exit 0, cryptographic receipt generated), but this was the CLI path, not the gateway-mediated path the mobile app will consume. Mobile implementation should proceed against the gateway API spec with the understanding that end-to-end integration testing requires Track D completion.
Gap Analysis Reality (from docs/strategy/ICN-Gap-Analysis-March-2026.md):
- Flow 1 (Governance): PROVEN end-to-end. This is the v1 mobile anchor.
- Flow 2 (Patronage): Merged but unverified at runtime. PatronageTracker exists (PR #1325) but hasn't been demo-tested.
- Flow 3 (Federation): Basic federation works, but settlement finality is undefined. The demo runs four coops on the same K3s cluster — not real cross-network federation. Mobile should not claim federation is production-ready.
- Flow 4 (Reporting): Merged but unverified. Depends on receipt chain completion (#1311).
Priority: Build mobile v1 around Flow 1 (governance). Add other flows as they're verified by the Sprint (Mar 17-30).
Flow 1: Governance ("Did the vote that authorized this action actually happen?")
Demo script: demo/scripts/flow-1-governance.sh
Persona: Harbor Homes Housing Cooperative
| Step | Gateway call | Mobile screen | User action |
|---|---|---|---|
| Create proposal | POST /v1/gov/proposals (budget: $12K spend) |
Participate → New Proposal | Fill title, amount, recipient, purpose |
| Open for voting | POST /v1/gov/proposals/{id}/open |
Proposal detail | Tap "Open for voting" (steward action) |
| Cast votes | POST /v1/gov/proposals/{id}/vote × N |
Proposal detail → Vote sheet | Select for/against/abstain + optional comment |
| View tally | GET /v1/gov/proposals/{id}/tally |
Proposal detail (updated) | See vote counts |
| Close voting | POST /v1/gov/proposals/{id}/close |
Proposal detail | Tap "Close voting" (steward action) |
| View proof | GET /v1/gov/proposals/{id}/proof |
Provenance panel | Tap "View proof" → see GovernanceProof with attestations |
Key mobile moment: The proof panel. Member taps "View proof" and sees every voter's Ed25519 attestation, the decision hash, and verification status. This is where ICN's value becomes tangible.
Flow 2: Patronage ("Why did this member get this distribution?")
Demo script: demo/scripts/flow-2-patronage.sh
Persona: BrightWorks Worker Cooperative
| Step | Mobile screen | Shows |
|---|---|---|
| View patronage allocation | Participate → Allocation detail | Amount, recipient, basis (NY Corp Law §93 via PatronageTracker) |
| Trace provenance | Provenance panel | Proposal → GovernanceProof → AllocationReceipt |
| Verify | Deep inspection | Full chain: governance decision → allocation → distribution formula |
Key mobile moment: Tapping "Why this amount?" on a patronage allocation and seeing the entire chain from governance vote to formula application.
Flow 3: Federation ("How do independent co-ops coordinate without a bureaucracy?")
Demo script: demo/scripts/flow-3-federation.sh
Persona: Finger Lakes CDN (federation of Harbor Homes, BrightWorks, River City Tool Library)
| Step | Mobile screen | Shows |
|---|---|---|
| View federation members | Groups → Federation entity | Member cooperatives, attestations, vouches |
| Federation proposal | Participate (federation scope) | Cross-entity proposal (join/leave/vouch/policy) |
| Vote as delegate | Proposal detail → Vote | Delegate action on behalf of member cooperative |
| Cross-entity attestation | Activity | Federation attestation event with proof |
Key mobile moment: Scope switching from "Harbor Homes (Member)" to "Finger Lakes CDN (Delegate)" and seeing the governance context change entirely — different proposal types, different threshold rules, different scope of authority.
Flow 4: Reporting ("Can this produce trustworthy reporting without admin overhead?")
Demo script: demo/scripts/flow-4-reporting.sh
| Step | Mobile screen | Shows |
|---|---|---|
| View activity stream | Activity (scope: cooperative) | All proof-backed events in chronological order |
| Filter by type | Activity filter | Proposals only, settlements only, etc |
| Drill into record | Activity → Detail | Full provenance chain for any event |
| Cross-scope view | Activity (scope: all) | Events across all memberships |
Key mobile moment: The Activity stream itself — showing that every record is proof-backed, every flow is traceable, and the audit trail is self-generating without manual overhead.
9. Identity and Device Reality Spec
What v1 honestly supports
| Feature | State | UX treatment |
|---|---|---|
| Local key generation | ✅ Working | icnctl id create → Ed25519 keypair + DID |
| Key storage | ✅ Working | age encryption in .ICN_DATA_DIR/identity/keypair.age |
| Challenge-response auth | ✅ Working | Sign nonce → JWT token (1hr expiry) |
| DID resolution | ✅ Working | GET /v1/identity/resolve/{did} |
| Export/import | ✅ Working (awkward) | icnctl id export/import — manual file transfer |
| Multi-device | ⚠️ Partial | `icnctl device [add |
| Social recovery | ⚠️ Designed | SDIS recovery flow exists in pilot-ui but not fully integrated |
| Key rotation | ⚠️ Partial | Rotation protocol v1 exists; v2 delegated keys planned |
| Biometric unlock | ❌ Not built | Must be added for mobile (Android Keystore / iOS Secure Enclave) |
Honest mobile UX for identity
Onboarding: Show the reality. "Your identity is stored on this device. If you lose this device, you will need your recovery phrase or recovery contacts to regain access."
Device management: Show current device, with clear indication that multi-device is limited. "To use ICN on another device, you'll need to export your identity from this device."
Recovery: Surface recovery setup prominently. Do not bury it. "Set up recovery now" should be a persistent prompt until completed.
Key operations: All signing happens locally via biometric unlock (when built) or device authentication. Never transmit private keys.
What the member sees in Profile → Identity
Identity
DID: did:icn:z6MkhaXg... [copy]
Created: 2026-03-15
Key type: Ed25519
Device
This device: Pixel 9 Pro (primary)
Status: Active
Last synced: 2 minutes ago
Recovery
Status: ⚠️ Not configured
[Set up recovery]
Export
[Export identity to another device]
10. QR Schema v1
Practical constraints
- Maximum payload: 2000 bytes (for reliable scanning across devices, per
icnctlimplementation usingqrcodecrate) - Encoding: JSON, optionally signed
- Must work in low-light, at distance, on cheap screens
QR payload format
{
"v": 1,
"type": "entity" | "proposal" | "obligation" | "identity" | "action",
"id": "<entity:icn:... or proposal ID or DID>",
"scope": "<optional entity context>",
"action": "<optional action hint: vote, confirm, inspect>",
"exp": "<optional expiry timestamp for dynamic codes>",
"sig": "<optional Ed25519 signature over payload minus sig field>"
}
Use cases (v1 only — no NFC, no AR)
| Use case | QR type | Payload | Mobile behavior |
|---|---|---|---|
| Identify an entity | entity |
Entity ID | Opens Groups → entity detail |
| Open a proposal | proposal |
Proposal ID + scope | Opens Participate → proposal detail |
| Confirm an obligation | obligation |
Obligation ID + action hint | Opens Participate → obligation with confirm action |
| Identity exchange | identity |
DID + optional scope | Opens Profile → trust panel for that identity |
| Summit workshop QR | action |
Scope + action hint | Opens relevant flow (demo-specific) |
Scan flow
- User opens scan mode (persistent camera, auto-detect, no "press to scan" button)
- QR detected → instant transition to relevant view
- If signed payload: verify signature before acting
- If expired: show "This code has expired" with option to proceed to the referenced object anyway
- If scope mismatch: prompt scope switch before opening
Dynamic QR (for person-to-person interactions)
For actions requiring counterparty confirmation (e.g., exchange settlement):
- Person A generates dynamic QR (rotating, short-lived, signed)
- Person B scans
- Both devices now share context via the signed payload
- Action confirmation screen appears on both devices
- Both confirm → operations queued and synced
Non-QR fallbacks (for devices without cameras or in low-light)
- Manual entry: User can type an entity ID or DID directly
- Nearby devices (future): Bluetooth proximity discovery
- Share link: Deep links that open the same views as QR scans
Appendix A: Existing Surfaces and Their Relationship to Mobile
The ecosystem map (icn-ecosystem-map.md) defines five front-end surfaces plus supporting tools. The mobile member app is a sixth surface that must converge with, not duplicate, these.
| Surface | Audience | State | Relationship to mobile |
|---|---|---|---|
| pilot-ui (web/pilot-ui/) | Members | Feature-complete PWA, 288KB. SDIS enrollment/proofs/recovery, steward dashboard, offline support, i18n (EN+ES) | Identity/wallet flows should inform mobile design. Critical caveat: pilot-ui is NOT yet wired to real icnd — the anchor-manager.js component is a stub. Phase 2 Track D wires it up. Pilot-ui flows are validated against local/mocked backends, not the live gateway. Port the UX patterns, but do not assume the API integration is proven. |
| React Native SDK (sdk/react-native/) | Members | Components: VotingScreen, BudgetManager, CooperativeManager, NotificationCenter, RecurringPaymentSetup | Starting point for mobile. Extend with scope switching, action queue, provenance views. |
| TypeScript SDK (sdk/typescript/) | Developers | @icn/client v0.1.0, OpenAPI-generated types |
Gateway API client for mobile use. Shared with Demo UI — both consume the same projection model. |
| Demo UI (not yet built) | Summit attendees | Single-page React + TS SDK app. Presentation instrument, NOT a product. Four keyboard-navigable scenes. | Shares the same gateway API and TypeScript SDK as mobile. The Demo UI and mobile app must use a shared projection model for proposals, proofs, and governance flows to avoid incompatible front-end representations at the Summit. Demo UI is built post Phase 2 Track D. |
| NYCN Platform (ny-coop-net) | Organizers | FastAPI + React/TS, 85% prod-ready. Missing: ICN receipt views, icn_service.py. |
Not directly related to mobile member app, but shares the pattern of anchoring decisions to ICN receipts. Receipt rendering should be consistent across NYCN and mobile. |
| TUI (icn-console) | Operators/devs | ratatui + crossterm. Dashboard, Members, Ledger, Governance, Trust tabs | Remains the serious operator surface. Mobile does not replace it. |
| Demo scripts (demo/scripts/) | Presenters | 4 flows, presenter mode, beat markers | Mobile v1 should support these flows for October demo. Note: demo scripts currently run simulated responses. Phase 2 Track D converts them to real icnctl calls. The governance demo (Flow 1) was tested end-to-end via CLI on Mar 17 (19 steps, exit 0, cryptographic receipt verified) — but this was the CLI flow, not the gateway-mediated flow the mobile app would consume. |
| ICN Website (icn-website) | Developers + Organizers | Astro, deployed to intercooperative.network. Live but stale stats. | Summit attendees will scan QR codes pointing here. QR schema (Section 10) should support website deep links. |
Appendix B: Gateway Endpoints Relevant to Mobile v1
Auth (required for all protected calls)
POST /v1/auth/challenge → { nonce, expires_in }
POST /v1/auth/verify → { token (JWT), expires_in }
Core governance (the demo-critical path)
POST /v1/gov/domains Create governance domain
GET /v1/gov/domains List domains
POST /v1/gov/proposals Create proposal
GET /v1/gov/proposals List proposals (paginated, filterable)
GET /v1/gov/proposals/{id} Get proposal detail
POST /v1/gov/proposals/{id}/open Open for voting
POST /v1/gov/proposals/{id}/vote Cast vote
POST /v1/gov/proposals/{id}/close Close and tally
GET /v1/gov/proposals/{id}/tally Vote counts
GET /v1/gov/proposals/{id}/proof Cryptographic proof
GET /v1/gov/proposals/{id}/discussion Discussion thread
POST /v1/gov/proposals/{id}/discussion/comments Add comment
POST /v1/gov/delegations Delegate vote
Cooperative management
POST /v1/coops Create cooperative
GET /v1/coops/{id} Get cooperative
POST /v1/coops/{id}/members Add member
DELETE /v1/coops/{id}/members Remove member
PUT /v1/coops/{id}/members/role Update role
Federation
GET /v1/federation/status Federation status
POST /v1/federation/init Initialize federation
GET /v1/federation/coops List federated coops
POST /v1/federation/coops/{id}/vouch Vouch for cooperative
POST /v1/federation/attestations Issue attestation
Identity
GET /v1/identity/resolve/{did} DID resolution
GET /v1/members/{coop_id}/{did} Member profile
WebSocket (real-time events)
Gateway supports WebSocket event streaming for live activity updates.
Appendix C: Sync State Model
Every operation on mobile moves through:
local_pending → syncing → network_confirmed → (optional: disputed | superseded)
Member-facing state labels
| Internal state | Member sees | Color |
|---|---|---|
local_pending |
"Saved on your device" | Gray |
syncing |
"Sending to network..." | Blue/animated |
network_confirmed |
"Confirmed by network" | Green |
disputed |
"Flagged for review" | Red |
superseded |
"Updated — review required" | Orange |
Offline behavior
| Action | Offline? | Behavior |
|---|---|---|
| View cached proposals | ✅ | From local cache |
| Cast vote | ✅ | Signed locally, queued for sync |
| Create proposal | ✅ | Stored locally, synced when online |
| View proofs | ⚠️ | Only if previously cached |
| Scope switching | ✅ | From cached membership data |
| View real-time activity | ❌ | Requires WebSocket connection |
Conflict handling
If state changes before sync (e.g., proposal amended while offline vote is pending):
- UI shows: "This proposal changed before your vote was confirmed"
- Member must re-review the updated proposal
- Member re-submits vote against current version
- Original local vote is discarded with explanation
Spec generated 2026-03-18. Updated 2026-03-18: charter templates shipped (Phase 1 complete, PRs #1336+#1337). Next update triggers: gateway scope expansion (treasury:read/write), mobile implementation reveals missing assumptions.