# Edut Secret System - Wallet-First Designation + Membership Spec ## Overview The Edut onboarding flow is deterministic and wallet-first: 1. Visitor requests designation intent from `edut.ai`. 2. Server issues one-time typed-data payload (`nonce`, `deadline`, `price`, `currency`). 3. Visitor signs intent with wallet (identity proof, no value transfer). 4. Server verifies signature and creates/updates designation record. 5. Visitor mints paid EDUT membership on-chain (intent proof). 6. Server confirms transaction and marks membership active. 7. Visitor downloads the EDUT platform app from post-mint success links. This flow is the pre-launch identity and commerce envelope. It is not a throwaway waitlist. ## User Experience Sequence (Continue Flow) 1. Initial page state: orb, identity text, footer links. 2. First click anywhere: globe spin intensifies, `continue` appears. 3. Click `continue`: wallet explainer appears. 4. User selects `I have a wallet` or `I need a wallet`. 5. `I need a wallet` shows install guidance and remains in-page. 6. `I have a wallet` triggers wallet connection request. 7. Page calls `POST /secret/wallet/intent`. 8. Wallet signs EIP-712 typed intent. 9. Page calls `POST /secret/wallet/verify`. 10. Page requests membership quote via `POST /secret/membership/quote`. 11. Wallet submits membership mint transaction on Base. 12. Page confirms via `POST /secret/membership/confirm` and/or status poll. 13. UI shows `acknowledged ยท {token}` when membership is active. 14. Post-mint success state presents `download your platform` links (Desktop/iOS/Android). 15. Member opens the app, signs in with the same wallet, and receives platform updates through app notifications. Privacy and Terms links bypass flow and navigate normally. ## Architecture ```text Landing page -> POST /secret/wallet/intent Wallet signs typed intent (EIP-712) Landing page -> POST /secret/wallet/verify Landing page -> POST /secret/membership/quote Wallet sends paid mint tx on Base Landing page -> POST /secret/membership/confirm Membership active -> acknowledged state Post-mint success -> app download links (Desktop/iOS/Android) ``` ## Core Commerce Rule 1. Membership is required to purchase marketplace offers. 2. Membership is not a product/module license. 3. Offer-specific licenses/entitlements are purchased separately. 4. Membership purchase delivers initial platform access (download entry point) immediately after activation. ## Infrastructure | Service | Domain / Endpoint | Purpose | |---------|-------------------|---------| | Landing UI | `edut.ai`, `edut.dev` | Continue flow + wallet intent/signature + membership mint UX | | API | `api.edut.ai/secret/wallet/intent` | Create one-time designation intent | | API | `api.edut.ai/secret/wallet/verify` | Verify signature and bind wallet identity | | API | `api.edut.ai/secret/membership/quote` | Return current payable membership quote | | API | `api.edut.ai/secret/membership/confirm` | Confirm membership tx and activation state | | Chain | Base | Membership mint settlement and evidence | | Database | `/var/lib/edut/secrets.db` | Durable designation + membership state | ## Deterministic State Machine `pending_signature` -> `signature_verified` -> `pending_membership_mint` -> `membership_active` Additional side states: - `intent_expired` - `quote_expired` - `tx_unconfirmed` - `rejected` (invalid signature, wrong chain, mismatched wallet) - `rate_limited` Rules: 1. No backwards transition except administrative recovery event with audit entry. 2. `membership_active` requires successful on-chain payment confirmation. 3. Signature and quote nonces are single-use; replay attempts are rejected. 4. Acknowledged UI state requires `membership_active`. ## API Contracts ### 1) Wallet Intent #### `POST /secret/wallet/intent` Request JSON: ```json { "address": "0xabc123...", "origin": "https://edut.ai", "locale": "en", "chain_id": 8453 } ``` Behavior: 1. Normalize and validate wallet address format. 2. Validate `origin` against allowlist. 3. Enforce rate limits (IP + address + rolling windows). 4. Generate designation `code`, `auth_token`, nonce, and intent TTL. 5. Persist `pending_signature` state. 6. Return typed-data envelope fields required for signing. Response: ```json { "intent_id": "wi_...", "designation_code": "0217073045482", "display_token": "0217-0730-4548-2", "nonce": "f2e9...", "issued_at": "2026-02-17T07:30:45Z", "expires_at": "2026-02-17T07:40:45Z", "domain_name": "EDUT Designation", "chain_id": 8453, "verifying_contract": "0x0000000000000000000000000000000000000000" } ``` ### 2) Wallet Verify #### `POST /secret/wallet/verify` Request JSON: ```json { "intent_id": "wi_...", "address": "0xabc123...", "chain_id": 8453, "signature": "0x..." } ``` Behavior: 1. Load pending intent by `intent_id`. 2. Verify not expired and not consumed. 3. Reconstruct typed payload exactly as issued. 4. Recover signer and compare to declared address. 5. Validate chain allowlist and origin. 6. Transition to `signature_verified` and `pending_membership_mint`. Response: ```json { "status": "signature_verified", "designation_code": "0217073045482", "display_token": "0217-0730-4548-2", "verified_at": "2026-02-17T07:31:12Z" } ``` ### 3) Membership Quote #### `POST /secret/membership/quote` Request JSON: ```json { "designation_code": "0217073045482", "address": "0xabc123...", "chain_id": 8453 } ``` Behavior: 1. Verify `signature_verified` status for designation/address pair. 2. Fetch current policy (`currency`, `amount`, `deadline`, `contract`). 3. Return quote payload for client-side transaction submission. Response: ```json { "quote_id": "mq_...", "chain_id": 8453, "currency": "USDC", "amount": "5.00", "amount_atomic": "5000000", "deadline": "2026-02-17T07:36:12Z", "contract_address": "0x...", "method": "mintMembership", "calldata": "0x..." } ``` ### 4) Membership Confirm #### `POST /secret/membership/confirm` Request JSON: ```json { "designation_code": "0217073045482", "quote_id": "mq_...", "tx_hash": "0x...", "address": "0xabc123...", "chain_id": 8453 } ``` Behavior: 1. Validate quote ownership and expiry. 2. Verify tx inclusion and success on allowed chain. 3. Validate minted membership recipient and amount policy. 4. Transition to `membership_active`. 5. Emit activation evidence receipt. Response: ```json { "status": "membership_active", "designation_code": "0217073045482", "display_token": "0217-0730-4548-2", "tx_hash": "0x...", "activated_at": "2026-02-17T07:33:09Z" } ``` ## Security Controls 1. Intent TTL and one-time nonce consumption. 2. Quote TTL with explicit `deadline`. 3. Strict origin allowlist for intent and verify endpoints. 4. Chain allowlist enforcement. 5. Signature and quote replay prevention. 6. IP + address rate limits on all public endpoints. 7. Deterministic audit trail for signature and payment confirmation. 8. No private key handling server-side. ## Data Model (SQLite) ### File: `/var/lib/edut/secrets.db` ```sql CREATE TABLE IF NOT EXISTS designations ( id INTEGER PRIMARY KEY AUTOINCREMENT, code TEXT NOT NULL UNIQUE, auth_token TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending_signature', wallet_address TEXT, chain_id INTEGER, intent_id TEXT UNIQUE, intent_nonce TEXT, intent_issued_at DATETIME, intent_expires_at DATETIME, signature TEXT, signature_verified_at DATETIME, membership_quote_id TEXT, membership_currency TEXT, membership_amount_atomic TEXT, membership_quote_expires_at DATETIME, membership_tx_hash TEXT, membership_activated_at DATETIME, origin TEXT, locale TEXT, created_at DATETIME DEFAULT (datetime('now')) ); CREATE INDEX idx_designations_code ON designations(code); CREATE INDEX idx_designations_wallet ON designations(wallet_address); CREATE INDEX idx_designations_status ON designations(status); CREATE INDEX idx_designations_intent ON designations(intent_id); CREATE INDEX idx_designations_quote ON designations(membership_quote_id); CREATE INDEX idx_designations_created ON designations(created_at); ``` ## Launch-Day Activation Messaging At launch, `membership_active` records are eligible for access-level updates and marketplace onboarding. ## NGINX Routing (Example) ```nginx location /secret/wallet/intent { proxy_pass http://127.0.0.1:9091; } location /secret/wallet/verify { proxy_pass http://127.0.0.1:9091; } location /secret/membership/quote { proxy_pass http://127.0.0.1:9091; } location /secret/membership/confirm { proxy_pass http://127.0.0.1:9091; } ``` ## Summary The wallet-first designation plus paid membership flow creates a deterministic two-factor identity and commitment chain: 1. signature proves wallet control, 2. paid mint proves intent, 3. membership gates all future marketplace purchases.