diff --git a/README.md b/README.md index c5cf2a0..870b460 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,20 @@ docs/ roadmap-membership-platform.md roadmap-status.md membership-pricing-policy.md + membership-tier-extension.md + failure-state-matrix.md + legal-copy-matrix.md + localization-qa-matrix.md + mobile-wallet-handoff.md + chain-operations-runbook.md + security-hardening-checklist.md + policy-hash-versioning.md + integration-test-plan.md + implementation-mapping.md + public-trust-page-spec.md + migration-policy-v1-to-v2.md + issuer-onboarding-pack.md + release-gate.md review-notes.md platform-spec-alignment-review.md contracts/ @@ -39,18 +53,24 @@ docs/ README.md chain-config.template.json contract-addresses.template.json + environment-invariants.md api/ secret-system.openapi.yaml + examples/ + secret-system.examples.md handoff/ membership-backend-checklist.md schemas/ offer.v1.schema.json entitlement.v1.schema.json issuer-manifest.v1.schema.json + evidence-receipt.v1.schema.json + launch-offers-catalog.v1.schema.json examples/ offer.v1.example.json entitlement.v1.example.json issuer-manifest.v1.example.json + launch-offers-catalog.v1.example.json README.md ``` diff --git a/docs/api/examples/secret-system.examples.md b/docs/api/examples/secret-system.examples.md new file mode 100644 index 0000000..9a0e351 --- /dev/null +++ b/docs/api/examples/secret-system.examples.md @@ -0,0 +1,182 @@ +# Secret System API Examples (v1) + +## 1) `POST /secret/wallet/intent` + +Request: + +```json +{ + "address": "0x3ea6cbf98d23e2cf7b6f4f9bb1fb4f50b710f2d5", + "origin": "https://edut.ai", + "locale": "en", + "chain_id": 8453 +} +``` + +Success (`200`): + +```json +{ + "intent_id": "wi_01HZZX2Q8R0FQFQ6B1VQ1N2P9J", + "designation_code": "0217073045482", + "display_token": "0217-0730-4548-2", + "nonce": "47f43f70d1288d4e", + "issued_at": "2026-02-17T07:30:45Z", + "expires_at": "2026-02-17T07:35:45Z", + "domain_name": "EDUT Designation", + "chain_id": 8453, + "verifying_contract": "0x0000000000000000000000000000000000000000" +} +``` + +Error (`429` rate limited): + +```json +{ + "error": "rate_limited", + "message": "Too many intent requests. Retry later." +} +``` + +## 2) `POST /secret/wallet/verify` + +Request: + +```json +{ + "intent_id": "wi_01HZZX2Q8R0FQFQ6B1VQ1N2P9J", + "address": "0x3ea6cbf98d23e2cf7b6f4f9bb1fb4f50b710f2d5", + "chain_id": 8453, + "signature": "0xabcdef..." +} +``` + +Success (`200`): + +```json +{ + "status": "signature_verified", + "designation_code": "0217073045482", + "display_token": "0217-0730-4548-2", + "verified_at": "2026-02-17T07:31:12Z" +} +``` + +Error (`400` intent expired): + +```json +{ + "error": "intent_expired", + "message": "Intent has expired. Request a new intent." +} +``` + +## 3) `POST /secret/membership/quote` + +Request: + +```json +{ + "designation_code": "0217073045482", + "address": "0x3ea6cbf98d23e2cf7b6f4f9bb1fb4f50b710f2d5", + "chain_id": 8453 +} +``` + +Success (`200`): + +```json +{ + "quote_id": "mq_01HZZX4F8VQXJ6A57R8P3SCB2W", + "chain_id": 8453, + "currency": "USDC", + "amount": "5.00", + "amount_atomic": "5000000", + "decimals": 6, + "deadline": "2026-02-17T07:36:12Z", + "contract_address": "0x1111111111111111111111111111111111111111", + "method": "mintMembership", + "calldata": "0xdeadbeef", + "value": "0x0", + "tx": { + "to": "0x1111111111111111111111111111111111111111", + "data": "0xdeadbeef", + "value": "0x0" + } +} +``` + +Error (`403` not verified): + +```json +{ + "error": "signature_not_verified", + "message": "Signature verification is required before quote issuance." +} +``` + +## 4) `POST /secret/membership/confirm` + +Request: + +```json +{ + "designation_code": "0217073045482", + "quote_id": "mq_01HZZX4F8VQXJ6A57R8P3SCB2W", + "tx_hash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "address": "0x3ea6cbf98d23e2cf7b6f4f9bb1fb4f50b710f2d5", + "chain_id": 8453 +} +``` + +Success (`200`): + +```json +{ + "status": "membership_active", + "designation_code": "0217073045482", + "display_token": "0217-0730-4548-2", + "tx_hash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "activated_at": "2026-02-17T07:33:09Z" +} +``` + +Error (`400` tx mismatch): + +```json +{ + "error": "tx_mismatch", + "message": "Transaction amount or destination does not match quote policy." +} +``` + +## 5) `POST /secret/notify` + +Request: + +```json +{ + "email": "user@example.com", + "designation_code": "0217073045482", + "designation_token": "0217-0730-4548-2", + "wallet": "0x3ea6cbf98d23e2cf7b6f4f9bb1fb4f50b710f2d5", + "locale": "en" +} +``` + +Success (`200`): + +```json +{ + "status": "saved" +} +``` + +Error (`422` invalid email): + +```json +{ + "error": "invalid_email", + "message": "Email format is invalid." +} +``` diff --git a/docs/chain-operations-runbook.md b/docs/chain-operations-runbook.md new file mode 100644 index 0000000..3464cca --- /dev/null +++ b/docs/chain-operations-runbook.md @@ -0,0 +1,50 @@ +# Chain Operations Runbook (Base, v1) + +## Scope + +Operational procedures for membership mint and checkout confirmation dependency on chain state. + +## Normal Operation + +1. Primary RPC healthy. +2. Confirmation endpoint verifies tx receipt and policy match. +3. Membership state transitions to `membership_active` only on valid confirmation. + +## Degraded Scenarios + +## RPC Outage + +1. Mark confirmation dependency degraded. +2. Switch to secondary RPC endpoint. +3. Re-run receipt verification. +4. If uncertain, fail closed and queue retry. + +## Reorg Risk + +1. Apply minimum confirmation depth policy. +2. If tx dropped/reorged, revert to `pending_membership_mint`. +3. Notify via deterministic status message; do not promote state. + +## Chain Congestion + +1. Quote remains authoritative until expiry. +2. Expired quote requires re-quote. +3. No off-policy amount overrides. + +## Safe Mode Triggers + +1. Conflicting tx results across RPC providers. +2. Contract bytecode mismatch at expected address. +3. Persistent receipt retrieval failures beyond threshold. + +Safe mode actions: + +1. Pause new confirmations. +2. Keep purchase state blocked. +3. Emit incident evidence. + +## Recovery + +1. Validate RPC consensus. +2. Reconcile pending confirms deterministically. +3. Resume confirmations after verification threshold restored. diff --git a/docs/deployment/environment-invariants.md b/docs/deployment/environment-invariants.md new file mode 100644 index 0000000..281c7c8 --- /dev/null +++ b/docs/deployment/environment-invariants.md @@ -0,0 +1,18 @@ +# Environment Invariants + +These invariants must hold for staging and production. + +## Required Invariants + +1. Chain ID in backend config matches allowed chain ID in API and frontend expectations. +2. Membership contract address in backend matches deployment registry. +3. Quote currency policy matches configured token addresses. +4. Origin allowlist includes only approved domains. +5. Fail-closed default behavior enabled for unknown membership/entitlement states. + +## Verification Checklist + +1. Intent endpoint returns expected chain and contract metadata. +2. Confirm endpoint rejects tx on wrong chain. +3. Checkout gate blocks non-members. +4. Runtime activation gate blocks non-active entitlements. diff --git a/docs/failure-state-matrix.md b/docs/failure-state-matrix.md new file mode 100644 index 0000000..ac13125 --- /dev/null +++ b/docs/failure-state-matrix.md @@ -0,0 +1,27 @@ +# Membership Flow Failure-State Matrix (v1) + +This matrix defines deterministic fail-closed behavior and user-facing outcomes. + +| Stage | Failure | Detection Source | System Action | User Surface | +|---|---|---|---|---| +| Intent | Rate limit | API guard | Block intent issuance | "Too many requests. Try again later." | +| Intent | Invalid origin | API allowlist | Reject request | "Request origin not allowed." | +| Verify | Intent expired | TTL check | Reject verify | "Intent expired. Start again." | +| Verify | Signature mismatch | Signature recovery | Reject verify + audit entry | "Signature could not be verified." | +| Quote | Signature not verified | State check | Deny quote | "Verify wallet signature first." | +| Quote | Quote expired | TTL check | Deny confirm | "Quote expired. Request a new quote." | +| Mint | Wallet reject tx | Wallet provider | No state change | "Membership mint was not approved." | +| Confirm | Wrong chain | Chain check | Reject confirm | "Transaction is on an unsupported chain." | +| Confirm | Amount mismatch | Quote/tx comparator | Reject confirm | "Transaction does not match quote." | +| Confirm | Recipient mismatch | Quote/tx comparator | Reject confirm | "Destination contract mismatch." | +| Confirm | Node unavailable | RPC health | Fail closed | "Unable to confirm transaction. Purchase stays blocked." | +| Notify | Invalid email | Input validation | Reject notify | "Invalid email format." | +| Checkout | No membership | Gate check | Block purchase | "Membership required." | +| Checkout | Membership suspended/revoked | Gate check | Block purchase | "Membership inactive. Contact support." | +| Activation | Entitlement not active | Gate check | Block runtime | "License inactive. Activation blocked." | + +## Invariants + +1. Unknown state defaults to blocked. +2. No failed transition may promote membership or entitlement state. +3. Every reject path produces structured audit evidence. diff --git a/docs/implementation-mapping.md b/docs/implementation-mapping.md new file mode 100644 index 0000000..ff2536b --- /dev/null +++ b/docs/implementation-mapping.md @@ -0,0 +1,25 @@ +# Implementation Mapping (Web -> Backend -> Runtime) + +## Web Repo Responsibilities + +1. Wallet-first UX and membership flow orchestration. +2. API contract and schema definitions. +3. Policy/legal/public messaging consistency. + +## Backend Responsibilities + +1. Intent/verify/quote/confirm/notify endpoints. +2. Deterministic state transitions and persistence. +3. Chain verification and policy hash enforcement. + +## Runtime/Kernel Responsibilities + +1. Membership and entitlement gates at activation points. +2. Fail-closed behavior for uncertain states. +3. Evidence receipt generation and retention. + +## Required Integration Contract + +1. Backend API shape follows `docs/api/secret-system.openapi.yaml`. +2. Policy/offer/entitlement payloads validate against schemas. +3. Runtime consumes entitlement state and policy hash from backend evidence. diff --git a/docs/integration-test-plan.md b/docs/integration-test-plan.md new file mode 100644 index 0000000..411c6a0 --- /dev/null +++ b/docs/integration-test-plan.md @@ -0,0 +1,22 @@ +# Integration Test Plan (Membership Commerce) + +## Objective + +Validate end-to-end behavior from wallet intent to membership-gated checkout. + +## E2E Scenarios + +1. Happy path membership activation. +2. Signature mismatch. +3. Quote expiry before tx submission. +4. Tx mismatch (amount/currency/recipient). +5. Membership suspended blocks checkout. +6. Active membership enables checkout quote. +7. Entitlement non-active blocks runtime activation. + +## Artifacts + +1. API request/response captures. +2. Tx hash and chain verification outputs. +3. Receipt/audit evidence IDs. +4. Pass/fail mapping to conformance vectors. diff --git a/docs/issuer-onboarding-pack.md b/docs/issuer-onboarding-pack.md new file mode 100644 index 0000000..3898d6a --- /dev/null +++ b/docs/issuer-onboarding-pack.md @@ -0,0 +1,50 @@ +# Issuer Onboarding Pack (v1) + +## Purpose + +This pack defines the minimum deterministic requirements for external issuers publishing offers on EDUT. + +## Issuer Entry Checklist + +1. Register issuer namespace (`issuer_id`). +2. Submit issuer manifest (`issuer_manifest.v1`). +3. Register signing keys and key-rotation contact. +4. Provide support channel and incident contact. +5. Accept marketplace policy and conformance obligations. + +## Offer Publish Checklist + +1. Offer payload validates against `offer.v1.schema.json`. +2. `member_only` policy is explicit. +3. Price/currency/chain fields are complete. +4. Entitlement type and scope are explicit. +5. Offer status set to `draft` first. +6. Policy hash generated and stored. +7. Review gate passed before `active`. + +## Policy Lint Checklist + +1. No missing required policy fields. +2. No unknown enum values. +3. No contradictory flags (for example, workspace-bound + transferable true unless explicitly supported). +4. Currency is supported (`USDC` or `ETH` in v1). +5. Amount is positive atomic integer. +6. Lifecycle transitions are valid (`draft -> active -> paused/retired`). + +## Runtime Expectations + +1. Issuer offers cannot bypass membership gate. +2. Entitlement activation must be fail-closed. +3. Revocation and suspension must propagate deterministically. + +## Incident Responsibilities + +1. Issuer must acknowledge critical entitlement issue within published SLA. +2. Issuer must provide rollback or pause decision path. +3. Issuer actions must preserve audit evidence. + +## Non-Negotiables + +1. No direct side-channel entitlement grants. +2. No hidden pricing paths outside quote/confirm policy. +3. No policy mutation without versioned update and evidence. diff --git a/docs/legal-copy-matrix.md b/docs/legal-copy-matrix.md new file mode 100644 index 0000000..1646b96 --- /dev/null +++ b/docs/legal-copy-matrix.md @@ -0,0 +1,17 @@ +# Legal Copy Alignment Matrix + +This matrix prevents drift between public surfaces and legal posture. + +| Surface | Required Message | Prohibited Message | +|---|---|---| +| Landing (`public/index.html`) | Wallet signature + paid membership unlocks access | Investment, yield, appreciation claims | +| Store (`public/store/index.html`) | Membership required for purchasing offers | "Membership includes all products forever" | +| Terms (`public/terms/index.html`) | Membership is utility access; licenses separate | Equity/ownership implications | +| Privacy (`public/privacy/index.html`) | Wallet/signature processing and optional notify email | Hidden collection claims inconsistent with implementation | +| Vision/spec docs | Deterministic governance and fail-closed controls | Speculative financial framing | + +## Hard Rules + +1. Membership language must always distinguish access rights from license rights. +2. Any copy introducing financial upside claims is blocked. +3. Any change to legal-critical copy requires review against this matrix. diff --git a/docs/localization-qa-matrix.md b/docs/localization-qa-matrix.md new file mode 100644 index 0000000..b2844c5 --- /dev/null +++ b/docs/localization-qa-matrix.md @@ -0,0 +1,35 @@ +# Localization QA Matrix (12 Languages) + +## Scope + +Validate membership-flow strings and legal-critical labels across all locale bundles. + +## Locales + +1. en +2. zh +3. es +4. ar +5. fr +6. pt +7. de +8. ja +9. ru +10. ko +11. hi +12. he + +## Required Key Sets + +1. core identity support keys (`definition`, `descriptor`, `acknowledged`, `privacy`, `terms`) +2. wallet flow keys (`continue_label`, `wallet_intro`, `wallet_connecting`, `wallet_signing`, `wallet_verifying`, `wallet_failed`) +3. membership flow keys (`membership_quoting`, `membership_minting`, `membership_confirming`, `membership_active`) +4. notify keys (`notify_me`, `notify_placeholder`, `notify_submit`, `notify_saved`, `notify_failed`) + +## QA Checks + +1. JSON parses successfully. +2. All required keys exist in each locale. +3. RTL locales (`ar`, `he`) render with per-node `dir` handling. +4. Strings preserve meaning for utility-access framing. +5. No locale introduces investment language. diff --git a/docs/membership-tier-extension.md b/docs/membership-tier-extension.md new file mode 100644 index 0000000..ecfd78e --- /dev/null +++ b/docs/membership-tier-extension.md @@ -0,0 +1,23 @@ +# Membership Tier Extension Spec + +## Purpose + +Define optional supply-based tiered membership pricing without breaking v1 flows. + +## Tier Model + +1. Tier boundaries based on total minted memberships. +2. Each tier defines currency and amount_atomic. +3. Price auto-selects by minted supply at quote time. + +## Compatibility + +1. Existing quote/confirm flow remains unchanged. +2. Tier metadata added to quote response (`tier_id`, `tier_label`). +3. Receipts persist tier metadata for audit. + +## Guardrails + +1. Floor policy still applies. +2. Tier transitions event-emitted. +3. Quotes lock tier price until expiry. diff --git a/docs/migration-policy-v1-to-v2.md b/docs/migration-policy-v1-to-v2.md new file mode 100644 index 0000000..bf7eeec --- /dev/null +++ b/docs/migration-policy-v1-to-v2.md @@ -0,0 +1,14 @@ +# Migration Policy: v1 to v2 + +## Rules + +1. v1 interfaces evolve additively only. +2. Breaking changes require v2 namespace. +3. v1 deprecation requires migration guide and overlap window. + +## Required v2 Deliverables + +1. Side-by-side API spec (`/v2`). +2. Schema migration map. +3. Backward compatibility notes. +4. Evidence continuity guarantees. diff --git a/docs/mobile-wallet-handoff.md b/docs/mobile-wallet-handoff.md new file mode 100644 index 0000000..bc0b85a --- /dev/null +++ b/docs/mobile-wallet-handoff.md @@ -0,0 +1,30 @@ +# Mobile Wallet Handoff UX Spec (v1) + +## Goal + +Provide deterministic cross-device path when user starts on desktop but wallet is on phone. + +## Entry Paths + +1. Desktop with extension wallet available -> direct connect. +2. Desktop without extension -> QR handoff to mobile wallet. +3. Mobile browser with wallet app -> deep-link connect. + +## Desktop QR Handoff + +1. User clicks `I have a wallet`. +2. If no injected provider detected, show QR panel. +3. QR encodes short-lived session handoff token. +4. Mobile wallet scan opens connect/sign flow. +5. Desktop polls handoff status until signature/tx complete or timeout. + +## Constraints + +1. Handoff token TTL short (recommended 5 minutes). +2. Single-use token; replay denied. +3. If timeout occurs, restart with new token. + +## Fail-Closed + +1. No completed handoff token -> no signature verify. +2. No membership confirm -> no acknowledged state. diff --git a/docs/policy-hash-versioning.md b/docs/policy-hash-versioning.md new file mode 100644 index 0000000..37df299 --- /dev/null +++ b/docs/policy-hash-versioning.md @@ -0,0 +1,29 @@ +# Policy Hash and Versioning Spec (v1) + +## Purpose + +Ensure each quote, purchase, and entitlement is provably bound to an exact policy snapshot. + +## Canonical Policy Snapshot + +1. Serialize policy object with stable key ordering. +2. Normalize numeric representations. +3. Remove non-policy metadata fields. + +## Hashing + +1. Compute `policy_hash = SHA-256(canonical_policy_json)`. +2. Store hex-encoded 64-char hash. +3. Include `policy_hash` in quote response, receipt, and entitlement record. + +## Versioning + +1. `policy_version` is semantic (`v1`, `v1.1`, etc.) for human readability. +2. `policy_hash` is authoritative for machine verification. +3. Breaking changes require new `policy_version` and migration note. + +## Enforcement + +1. Checkout confirm rejects if tx-linked quote policy hash differs from current quote policy hash. +2. Entitlement activation uses stored `policy_hash`; no retroactive mutation. +3. Historical purchases remain tied to their original policy hash. diff --git a/docs/public-trust-page-spec.md b/docs/public-trust-page-spec.md new file mode 100644 index 0000000..f1fdd43 --- /dev/null +++ b/docs/public-trust-page-spec.md @@ -0,0 +1,19 @@ +# Public Trust Page Spec + +## Purpose + +Provide transparent operational facts without exposing private internals. + +## Required Sections + +1. Active chain and chain ID. +2. Contract addresses (membership, offer registry, entitlement). +3. Current membership pricing policy hash/version. +4. API health summary for intent/verify/quote/confirm. +5. Last policy update timestamp. + +## Non-Goals + +1. No private key details. +2. No internal infrastructure topology. +3. No speculative roadmap commitments. diff --git a/docs/release-gate.md b/docs/release-gate.md new file mode 100644 index 0000000..1d6acbd --- /dev/null +++ b/docs/release-gate.md @@ -0,0 +1,37 @@ +# Release Gate: Membership Platform (v1) + +This gate controls deploy/no-deploy decisions for membership-gated commerce changes. + +## Gate Categories + +1. Contract/API compatibility +2. Conformance vectors +3. Security checks +4. Legal/policy checks +5. Observability checks + +## Deploy Criteria (All Required) + +1. `docs/conformance/membership-gating-vectors.md`: all vectors pass. +2. OpenAPI and implementation remain compatible. +3. Signature replay tests pass. +4. Quote expiry tests pass. +5. Tx mismatch tests pass. +6. Membership gate blocks non-members in all checkout paths. +7. Terms/privacy copy still match utility-access framing. +8. Structured logs and metrics are emitted for each state transition. + +## No-Deploy Triggers + +1. Any conformance vector failure. +2. Any path that allows purchase without active membership. +3. Any activation path that proceeds with non-active entitlement. +4. Any missing audit evidence on successful purchase. +5. Any breaking API change without version bump and migration note. + +## Evidence Bundle Required for Release + +1. Test result artifact references. +2. Contract address/version snapshot. +3. Policy hash snapshot. +4. Change summary and rollback plan. diff --git a/docs/roadmap-status.md b/docs/roadmap-status.md index 83afdb7..5deeccd 100644 --- a/docs/roadmap-status.md +++ b/docs/roadmap-status.md @@ -12,8 +12,8 @@ Status key: 2. Freeze token taxonomy: `DONE` 3. Finalize membership contract interface targets: `DONE` 4. Lock signature + intent protocol: `DONE` -5. Add membership mint transaction stage in web flow: `IN_PROGRESS` -6. Implement membership gate in marketplace checkout: `PENDING` +5. Add membership mint transaction stage in web flow: `DONE` (frontend path implemented; backend endpoints pending) +6. Implement membership gate in marketplace checkout: `IN_PROGRESS` (store scaffold + gate logic implemented; live API pending) 7. Ship offer registry schema: `DONE` 8. Ship entitlement purchase schema/pipeline contracts: `IN_PROGRESS` 9. Bind entitlements to runtime activation: `PENDING` @@ -33,10 +33,15 @@ Implemented now: 6. Interface target document for contracts/APIs. 7. Pricing policy with USD 5 floor rule. 8. Terms utility-only non-investment clause. +9. Store page upgraded from static to live-state scaffold with membership gate behavior. +10. OpenAPI contract + request/response examples for secret-system endpoints. +11. Conformance vectors + failure matrix + release gate + security checklist. +12. Deployment templates + invariants + chain operations runbook. +13. Issuer onboarding pack, migration policy, trust page spec, and integration mapping docs. Remaining in this repo: -1. Build live store behavior on top of the static skeleton once checkout APIs are available. +1. Wire live store checkout flow to production marketplace APIs when available. 2. Replace deployment templates with real contract addresses after chain deployment. Cross-repo dependencies (kernel/backend/contracts): diff --git a/docs/schemas/evidence-receipt.v1.schema.json b/docs/schemas/evidence-receipt.v1.schema.json new file mode 100644 index 0000000..30d397e --- /dev/null +++ b/docs/schemas/evidence-receipt.v1.schema.json @@ -0,0 +1,71 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://edut.ai/schemas/evidence-receipt.v1.schema.json", + "title": "EDUT Evidence Receipt Schema v1", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "receipt_id", + "event_type", + "wallet", + "timestamp", + "hash" + ], + "properties": { + "schema_version": { + "type": "string", + "const": "evidence_receipt.v1" + }, + "receipt_id": { + "type": "string" + }, + "event_type": { + "type": "string", + "enum": [ + "membership_mint", + "membership_confirm", + "offer_checkout_quote", + "offer_checkout_confirm", + "entitlement_mint", + "entitlement_state_change" + ] + }, + "wallet": { + "type": "string", + "pattern": "^0x[a-fA-F0-9]{40}$" + }, + "designation_code": { + "type": ["string", "null"] + }, + "offer_id": { + "type": ["string", "null"] + }, + "quote_id": { + "type": ["string", "null"] + }, + "entitlement_id": { + "type": ["string", "null"] + }, + "tx_hash": { + "type": ["string", "null"], + "pattern": "^0x[a-fA-F0-9]{64}$" + }, + "chain_id": { + "type": ["integer", "null"], + "minimum": 1 + }, + "policy_hash": { + "type": ["string", "null"], + "pattern": "^[a-fA-F0-9]{64}$" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "hash": { + "type": "string", + "pattern": "^[a-fA-F0-9]{64}$" + } + } +} diff --git a/docs/schemas/examples/launch-offers-catalog.v1.example.json b/docs/schemas/examples/launch-offers-catalog.v1.example.json new file mode 100644 index 0000000..3fb1870 --- /dev/null +++ b/docs/schemas/examples/launch-offers-catalog.v1.example.json @@ -0,0 +1,25 @@ +{ + "schema_version": "launch_offers_catalog.v1", + "catalog_id": "launch-2026-operator", + "offers": [ + { + "offer_id": "edut.crm.pro.annual", + "title": "EDUT CRM Pro", + "summary": "Workspace-bound CRM module with governance and evidence integration.", + "price": "199.00", + "currency": "USDC", + "member_only": true, + "workspace_bound": true + }, + { + "offer_id": "edut.invoicing.core.annual", + "title": "EDUT Invoicing Core", + "summary": "Invoicing workflow module for member workspaces.", + "price": "99.00", + "currency": "USDC", + "member_only": true, + "workspace_bound": true + } + ], + "published_at": "2026-02-17T00:00:00Z" +} diff --git a/docs/schemas/launch-offers-catalog.v1.schema.json b/docs/schemas/launch-offers-catalog.v1.schema.json new file mode 100644 index 0000000..7149402 --- /dev/null +++ b/docs/schemas/launch-offers-catalog.v1.schema.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://edut.ai/schemas/launch-offers-catalog.v1.schema.json", + "title": "EDUT Launch Offers Catalog v1", + "type": "object", + "additionalProperties": false, + "required": ["schema_version", "catalog_id", "offers", "published_at"], + "properties": { + "schema_version": { "type": "string", "const": "launch_offers_catalog.v1" }, + "catalog_id": { "type": "string" }, + "offers": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["offer_id", "title", "price", "currency", "member_only"], + "properties": { + "offer_id": { "type": "string" }, + "title": { "type": "string" }, + "summary": { "type": "string" }, + "price": { "type": "string" }, + "currency": { "type": "string", "enum": ["USDC", "ETH"] }, + "member_only": { "type": "boolean" }, + "workspace_bound": { "type": "boolean" } + } + } + }, + "published_at": { "type": "string", "format": "date-time" } + } +} diff --git a/docs/security-hardening-checklist.md b/docs/security-hardening-checklist.md new file mode 100644 index 0000000..6287a84 --- /dev/null +++ b/docs/security-hardening-checklist.md @@ -0,0 +1,38 @@ +# Security Hardening Checklist (Membership Flow) + +## Wallet Intent and Signature + +1. Enforce strict nonce uniqueness. +2. Enforce intent TTL. +3. Enforce origin allowlist. +4. Verify chain ID against allowlist. +5. Reject malformed or oversized signatures. +6. Reject replayed `intent_id`. + +## Quote and Confirm + +1. Use quote TTL and one-time confirmation semantics. +2. Bind quote to wallet and designation. +3. Confirm tx amount, currency, and contract destination exactly. +4. Confirm tx success status and finality threshold. +5. Idempotent confirm handling by `tx_hash` + `quote_id`. + +## API Controls + +1. Rate limits on intent, verify, quote, confirm, notify. +2. Request size limits. +3. Structured error responses without sensitive internals. +4. Correlation ID logging for all transitions. + +## Data Integrity + +1. Append-only audit records for state transitions. +2. Immutable receipt hash generation. +3. Versioned policy hash persistence with each quote and purchase. + +## Operational Safety + +1. Fail closed on RPC/node uncertainty. +2. Multi-RPC fallback with deterministic selection policy. +3. Emergency pause path for mint/checkout. +4. Key rotation runbook for issuer and system keys. diff --git a/public/store/index.html b/public/store/index.html index 084d804..46d7710 100644 --- a/public/store/index.html +++ b/public/store/index.html @@ -18,7 +18,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } - .container { max-width: 880px; margin: 0 auto; } + .container { max-width: 960px; margin: 0 auto; } a { color: #2c2c2c; text-underline-offset: 2px; } .back { display: inline-block; @@ -43,7 +43,7 @@ .grid { display: grid; gap: 14px; - grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); margin-bottom: 20px; } .card { @@ -80,6 +80,48 @@ } .state.ok { border-color: #6f8d72; color: #3f6545; } .state.block { border-color: #9d7676; color: #7c4a4a; } + .state.warn { border-color: #99834b; color: #6d5b30; } + .actions { + display: flex; + gap: 10px; + flex-wrap: wrap; + margin-top: 12px; + } + button { + border: 1px solid #c2c8d0; + background: #ffffff; + padding: 7px 10px; + font-family: 'IBM Plex Mono', 'Courier New', monospace; + font-size: 11px; + letter-spacing: 0.08em; + text-transform: uppercase; + color: #3d434a; + cursor: pointer; + } + button:hover { border-color: #8c949d; } + button:disabled { + cursor: not-allowed; + opacity: 0.5; + } + select { + border: 1px solid #c2c8d0; + background: #ffffff; + padding: 6px 8px; + font-family: 'IBM Plex Mono', 'Courier New', monospace; + font-size: 11px; + color: #3d434a; + } + .status-log { + margin-top: 12px; + border-top: 1px solid #d0d5db; + padding-top: 10px; + font-size: 11px; + color: #60666f; + line-height: 1.6; + min-height: 40px; + white-space: pre-wrap; + } + .mono { font-family: 'IBM Plex Mono', 'Courier New', monospace; } .foot { margin-top: 20px; border-top: 1px solid #d0d5db; @@ -94,40 +136,255 @@
← Back

EDUT Store

-

Membership-gated checkout states (preview skeleton)

+

Membership-gated checkout behavior (live-state scaffold)

-

State A

-

Wallet connected, no membership

-

Checkout is blocked. User is prompted to mint membership first.

- membership required +

Wallet + Membership

+

Wallet: not connected

+

Membership status: unknown

+

Gate decision: blocked

+ membership required +
+ + + + +
+
No checks run yet.
-

State B

-

Membership active

-

Offers can be quoted and purchased. Entitlement mint becomes available.

- checkout enabled +

Offer Skeleton

+

EDUT CRM Pro

+

Price: 199.00 USDC

+

Policy: member-only, workspace-bound, non-transferable

+

Action chain: membership check -> quote -> wallet confirm -> entitlement receipt

+
+ +
+
Checkout is blocked until membership is active.
-

State C

-

Membership suspended or revoked

-

Checkout and activation both fail closed until state returns to active.

- fail-closed +

Fail-Closed States

+

No membership: checkout blocked.

+

Suspended/revoked: checkout and activation blocked.

+

Unknown state or API error: blocked by default.

+ default deny
-
-

Offer Skeleton

-

EDUT CRM Pro

-

Price: 199.00 USDC

-

Policy: member-only, workspace-bound, non-transferable

-

Action: membership check -> quote -> wallet confirm -> entitlement receipt

-
- -

This page is a static contract between UX and policy: membership gates purchasing; entitlement gates runtime.

+

This page is intentionally deterministic: if membership cannot be confirmed, purchase remains blocked.

+ +