From 51d85b9a445b1235fdb95b1d1cbe234b128285a2 Mon Sep 17 00:00:00 2001 From: iTinkerBell Date: Thu, 13 Nov 2025 15:38:18 -0500 Subject: [PATCH 1/4] Badging NFT Integration Draft --- Badging System/Badging NFT Workflow.md | 109 +++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 Badging System/Badging NFT Workflow.md diff --git a/Badging System/Badging NFT Workflow.md b/Badging System/Badging NFT Workflow.md new file mode 100644 index 0000000..1fc825d --- /dev/null +++ b/Badging System/Badging NFT Workflow.md @@ -0,0 +1,109 @@ +# Boost Badging System – NFT Integration + +## Overview + +This document outlines a Solana-based badging flow that mints directly to recipient wallets or stores badges in the token contract (when no wallet is provided), supports email-triggered claims, and records all badge lifecycle events. The token contract includes built-in vault functionality for storing unclaimed badges. The implementation window is estimated at three weeks. + +```mermaid +sequenceDiagram + autonumber + participant FE as Frontend + participant IPFS as IPFS Service + participant DB as Database + participant Admin as Admin Wallet + participant Sol as Token Contract
(with vault functionality) + participant Mail as Mailing Service + participant User as User (with email) + participant Claim as Claim Service + participant Wallet as User Wallet + + FE->>IPFS: Submit user + badge payload + IPFS-->>FE: Return URI + CID metadata + FE->>DB: Persist issuance record (user data, URI, flags) + Admin->>FE: Initiate mint (via frontend with admin wallet) + FE->>Admin: Request transaction signing (token IDs, URI, wallet) + Admin->>FE: Sign mint or batch mint transaction + FE->>Sol: Send mint transaction + Sol-->>Wallet: Mint badge to user wallet (if provided) + Sol-->>Sol: Store badge in contract (no wallet address) + Sol-->>DB: Emit confirmation event (tx signatures) + + Sol-->>Mail: Trigger notification payload (wallet vs stored in contract) + Mail-->>User: Send email (direct badge info or claim instructions) + + Note over Claim,DB: Claim service fetches record using URI
and retrieves registered email address + + User->>FE: Initiate claim request (via frontend) + FE->>Claim: Request verification code + Claim->>DB: Generate & store one-time verification code (email, URI, timestamp, expiry) + Claim->>Mail: Send verification code to mailing service + Mail-->>User: Send one-time verification code + User->>FE: Input verification code + FE->>Claim: Submit verification code + Claim->>DB: Retrieve stored code & validate (code, rate limits, eligibility) + Claim->>FE: Prompt for public wallet address + FE->>User: Display wallet address input + User->>FE: Provide new wallet address + FE->>Claim: Submit wallet address + Claim->>DB: Update claim intent, log timestamp + Claim->>Mail: Send claim request email to admin + Mail-->>Admin: Notify admin of claim request (URI, token ID, wallet) + Admin->>FE: Initiate transfer (via frontend with admin wallet) + FE->>Admin: Request transaction signing (from contract to wallet) + Admin->>FE: Sign transfer transaction + FE->>Sol: Send transfer transaction + Sol-->>Wallet: Deliver claimed badge to user wallet + Sol-->>DB: Record claim completion (tx signature, wallet) + Mail-->>User: Send claim confirmation email + + Note over DB: Maintain full lifecycle history
(metadata hash, issuance, claim attempts, completion) +``` + +--- + +## End-to-End Workflow + +1. **Preparation** + - Frontend retrieves token catalogue and recipient roster. + - Admin selects badge set (single or batch) and recipients. + +2. **Metadata & Persistence** + - Frontend submits badge issuance payload to the IPFS service. + - IPFS returns content URI plus derived metadata (hash, gateway URL). + - Application persists issuance record in the database, including user data, payload hash, claim eligibility flags, and URI references. + +3. **Minting** + - Admin initiates mint via frontend with admin wallet. Frontend requests transaction signing from admin. + - Admin signs mint or batch mint transaction (supplying recipient wallet if available, token IDs, and metadata URI). + - Frontend sends the signed transaction to the token contract. + - Token contract (with built-in vault functionality) validates call and mints tokens: + - **If wallet provided**: Routes tokens directly to user wallets. + - **If no wallet provided**: Stores tokens in the contract's internal storage (vault functionality). + +4. **Notification** + - Post-confirmation hook (webhook or listener) enqueues email template jobs. + - Mailing list service delivers: + - **Direct wallet recipients** – badge details and blockchain links. + - **Contract-stored recipients** – claim instructions, emphasizing security posture. + +5. **Claim (Contract-Stored Tokens Only)** + - User initiates claim request via frontend (using claim service link from email). Frontend requests verification code from claim service. + - Claim service looks up issuance by URI and extracts the registered email. + - Claim service generates and stores one-time verification code in database (with email, URI, timestamp, expiry) and sends it to mailing service. + - Mailing service sends one-time verification code to user via email and enforces rate limits. + - User inputs verification code through frontend. Frontend submits code to claim service. + - Claim service retrieves stored code from database and validates (code, rate limits, eligibility). + - On success, frontend prompts user for a self-custodial public wallet address. + - User provides wallet address through frontend. Frontend submits wallet address to claim service. + - Claim service updates claim intent in database and sends claim request email to Admin, including URI, token ID, and user's wallet address. + - Admin receives claim request notification via email. + - Admin initiates transfer via frontend with admin wallet. Frontend requests transaction signing from admin. + - Admin signs transfer transaction (from contract storage to user wallet). Frontend sends the signed transaction to token contract. + - System updates database with claim completion timestamp, destination wallet, and transaction signature. + - Confirmation email is sent to the claimant. + +6. **Auditing & Reporting** + - Dashboard surfaces mint/claim status, IPFS hashes, and notification delivery logs. + - Scheduled jobs reconcile on-chain state with database records. + +--- From 93230188018848749c922c7601c498aad88db473 Mon Sep 17 00:00:00 2001 From: iTinkerBell Date: Thu, 20 Nov 2025 16:11:30 -0500 Subject: [PATCH 2/4] Draft #2 --- Badging System/Badging NFT Workflow.md | 416 ++++++++++++++++++++----- 1 file changed, 335 insertions(+), 81 deletions(-) diff --git a/Badging System/Badging NFT Workflow.md b/Badging System/Badging NFT Workflow.md index 1fc825d..326097c 100644 --- a/Badging System/Badging NFT Workflow.md +++ b/Badging System/Badging NFT Workflow.md @@ -1,8 +1,90 @@ -# Boost Badging System – NFT Integration +# Boost Badging System – NFT-Integration Plan ## Overview -This document outlines a Solana-based badging flow that mints directly to recipient wallets or stores badges in the token contract (when no wallet is provided), supports email-triggered claims, and records all badge lifecycle events. The token contract includes built-in vault functionality for storing unclaimed badges. The implementation window is estimated at three weeks. +Refined Solana-based badging flow that supports two badge types: + +- **Blockchain-backed badges** – minted to wallets or stored inside the token contract until claimed. +- **Database-only badges** – managed purely inside the application database with no blockchain touchpoints or wallet requirement. + +Both types share the same metadata and notification pipeline. The implementation window is estimated at three weeks. + +--- + +## End-to-End Workflow + +### Admin + +1. **Preparation** + - Admin retrieves token catalogue and recipient roster after metric evaluation via frontend. + - Admin selects badge set (single or batch) and recipients. + +2. **Metadata & Persistence** + - Admin submits badge issuance payload to the IPFS service via frontend. + - IPFS returns content URI plus derived metadata (hash, gateway URL). + - Application persists issuance record in the database, including user data, claim eligibility flags, and URI references. + +3. **Minting / Issuance** + - **Blockchain-backed badges** + - Admin initiates mint via frontend with admin wallet. Frontend requests transaction signing from admin. + - Admin signs mint or batch mint transaction (supplying recipient wallet if available, token IDs, and metadata URI). + - Frontend sends the signed transaction to the token contract. + - Token contract (with built-in vault functionality) validates call and mints tokens: + - If wallet provided: Routes tokens directly to user wallets. + - If no wallet provided: Stores tokens in the contract's internal storage (vault functionality). + - Token contract emits confirmation event with transaction signatures to the database. + - Post-confirmation hook triggers notification payload to mailing service (indicating whether badge was sent to wallet or stored in contract). + - Mailing service sends email to user (no clickable links; instead prompt them to log into boost.org): + - Direct wallet recipients – badge details and blockchain links. + - Contract-stored recipients – claim instructions, emphasizing security posture. + - **Database-only badges** + - Application marks the issuance as "database-only" and stores the badge entirely in the database (no wallet required). + - Database generates database-only badge notification and triggers mailing service. + - Mailing service sends badge email to user. + +4. **Claim Processing (Blockchain-backed / Contract-Stored Only)** + - Admin receives webhook notification when user submits a claim request. + - Admin initiates transfer via frontend with admin wallet. Frontend requests transaction signing (from contract to wallet). + - Admin signs transfer transaction. + - Frontend sends the signed transfer transaction to the token contract. + - Token contract delivers the claimed badge to the user wallet. + - System records claim completion in the database (transaction signature, wallet, timestamp). + - Mailing service sends claim confirmation email to the user. + +5. **Auditing & Reporting** + - Admin accesses dashboard to view mint/claim status, IPFS hashes, and notification delivery logs. + - Database maintains full lifecycle history (metadata hash, issuance, claim selections, completion). + +--- + +### User + +1. **Receiving Badge Notifications** + - User receives email notification about badge issuance (no clickable links, instead prompt them to log into boost.org): + - **Blockchain-backed badges (direct wallet)**: Email contains badge details. + - **Blockchain-backed badges (contract-stored)**: Email contains claim instructions. + - **Database-only badges**: Email contains badge details. + +2. **Viewing Badge Notifications (Database-only Badges)** + - User logs into the frontend. + - User views badge notification history. + - User can view database-only badges without wallet submission or admin transfer. + +3. **Claiming Badges (Blockchain-backed / Contract-Stored Only)** + - User logs into the frontend and views pending claim notifications. + - Frontend requests pending contract-stored badges from the claim service. + - Claim service queries the database for pending badge notifications and returns selectable notifications to the frontend. + - User selects one or more badges and provides wallet address(es) (one wallet can be used for multiple badges, or separate wallets for each badge), then submits the claim request. + - Frontend sends the claim selection (URI, token ID, wallet) to the claim service. + - Claim service updates the database with claim intent details (URI, token ID, wallet, timestamp). + - Claim service sends claim request payload (URI, token ID, wallet) to admin webhook. + - User waits for admin to process the claim request. + - User receives claim confirmation email once the badge is transferred to their wallet. + - **Note**: Database-only badges skip this section entirely – users already "own" the badge in the portal and can view without wallet submission or admin transfer. + +--- + +## Workflow Diagram ```mermaid sequenceDiagram @@ -13,6 +95,7 @@ sequenceDiagram participant Admin as Admin Wallet participant Sol as Token Contract
(with vault functionality) participant Mail as Mailing Service + participant Hook as Admin Webhook participant User as User (with email) participant Claim as Claim Service participant Wallet as User Wallet @@ -20,90 +103,261 @@ sequenceDiagram FE->>IPFS: Submit user + badge payload IPFS-->>FE: Return URI + CID metadata FE->>DB: Persist issuance record (user data, URI, flags) - Admin->>FE: Initiate mint (via frontend with admin wallet) - FE->>Admin: Request transaction signing (token IDs, URI, wallet) - Admin->>FE: Sign mint or batch mint transaction - FE->>Sol: Send mint transaction - Sol-->>Wallet: Mint badge to user wallet (if provided) - Sol-->>Sol: Store badge in contract (no wallet address) - Sol-->>DB: Emit confirmation event (tx signatures) - - Sol-->>Mail: Trigger notification payload (wallet vs stored in contract) - Mail-->>User: Send email (direct badge info or claim instructions) - - Note over Claim,DB: Claim service fetches record using URI
and retrieves registered email address - - User->>FE: Initiate claim request (via frontend) - FE->>Claim: Request verification code - Claim->>DB: Generate & store one-time verification code (email, URI, timestamp, expiry) - Claim->>Mail: Send verification code to mailing service - Mail-->>User: Send one-time verification code - User->>FE: Input verification code - FE->>Claim: Submit verification code - Claim->>DB: Retrieve stored code & validate (code, rate limits, eligibility) - Claim->>FE: Prompt for public wallet address - FE->>User: Display wallet address input - User->>FE: Provide new wallet address - FE->>Claim: Submit wallet address - Claim->>DB: Update claim intent, log timestamp - Claim->>Mail: Send claim request email to admin - Mail-->>Admin: Notify admin of claim request (URI, token ID, wallet) - Admin->>FE: Initiate transfer (via frontend with admin wallet) - FE->>Admin: Request transaction signing (from contract to wallet) - Admin->>FE: Sign transfer transaction - FE->>Sol: Send transfer transaction - Sol-->>Wallet: Deliver claimed badge to user wallet - Sol-->>DB: Record claim completion (tx signature, wallet) - Mail-->>User: Send claim confirmation email - - Note over DB: Maintain full lifecycle history
(metadata hash, issuance, claim attempts, completion) + alt Blockchain-backed badge + Admin->>FE: Initiate mint (via frontend with admin wallet) + FE->>Admin: Request transaction signing (token IDs, URI, wallet) + Admin->>FE: Sign mint or batch mint transaction + FE->>Sol: Send mint transaction + Sol-->>Wallet: Mint badge to user wallet (if provided) + Sol-->>Sol: Store badge in contract (no wallet address) + Sol-->>DB: Emit confirmation event (tx signatures) + + Sol-->>Mail: Trigger notification payload (wallet vs stored in contract) + Mail-->>User: Send email (direct badge info or claim instructions) + + Note over Claim,DB: Claim service queries DB for contract-stored badges
and associated recipient metadata + + User->>FE: Login & view claim notifications + FE->>Claim: Request pending contract-stored badges + Claim->>DB: Query pending badge notifications + Claim-->>FE: Return selectable notifications + User->>FE: Select badges + FE->>Claim: Submit claim selection (URI, token ID, wallet) with wallet address(es) + Claim->>DB: Update claim intent, log timestamp + Claim->>Hook: Send claim request payload (URI, token ID, wallet) + Hook-->>Admin: Notify admin via webhook + Admin->>FE: Initiate transfer (via frontend with admin wallet) + FE->>Admin: Request transaction signing (from contract to wallet) + Admin->>FE: Sign transfer transaction + FE->>Sol: Send transfer transaction + Sol-->>Wallet: Deliver claimed badge to user wallet + Sol-->>DB: Record claim completion (tx signature, wallet) + Mail-->>User: Send claim confirmation email + else Database-only badge + DB->>Mail: Generate database-only badge notification + Mail-->>User: Send badge email (no wallet required) + User->>FE: View badge notification history + Note over DB: Database tracks issuance, views, and acknowledgements
without blockchain transactions + end + + Note over DB: Maintain full lifecycle history
(metadata hash, issuance, claim selections, completion) ``` --- -## End-to-End Workflow +## Database Schema -1. **Preparation** - - Frontend retrieves token catalogue and recipient roster. - - Admin selects badge set (single or batch) and recipients. +```mermaid +erDiagram + users { + UUID id PK + VARCHAR email UK + VARCHAR wallet_address + TIMESTAMP created_at + TIMESTAMP updated_at + } -2. **Metadata & Persistence** - - Frontend submits badge issuance payload to the IPFS service. - - IPFS returns content URI plus derived metadata (hash, gateway URL). - - Application persists issuance record in the database, including user data, payload hash, claim eligibility flags, and URI references. - -3. **Minting** - - Admin initiates mint via frontend with admin wallet. Frontend requests transaction signing from admin. - - Admin signs mint or batch mint transaction (supplying recipient wallet if available, token IDs, and metadata URI). - - Frontend sends the signed transaction to the token contract. - - Token contract (with built-in vault functionality) validates call and mints tokens: - - **If wallet provided**: Routes tokens directly to user wallets. - - **If no wallet provided**: Stores tokens in the contract's internal storage (vault functionality). - -4. **Notification** - - Post-confirmation hook (webhook or listener) enqueues email template jobs. - - Mailing list service delivers: - - **Direct wallet recipients** – badge details and blockchain links. - - **Contract-stored recipients** – claim instructions, emphasizing security posture. - -5. **Claim (Contract-Stored Tokens Only)** - - User initiates claim request via frontend (using claim service link from email). Frontend requests verification code from claim service. - - Claim service looks up issuance by URI and extracts the registered email. - - Claim service generates and stores one-time verification code in database (with email, URI, timestamp, expiry) and sends it to mailing service. - - Mailing service sends one-time verification code to user via email and enforces rate limits. - - User inputs verification code through frontend. Frontend submits code to claim service. - - Claim service retrieves stored code from database and validates (code, rate limits, eligibility). - - On success, frontend prompts user for a self-custodial public wallet address. - - User provides wallet address through frontend. Frontend submits wallet address to claim service. - - Claim service updates claim intent in database and sends claim request email to Admin, including URI, token ID, and user's wallet address. - - Admin receives claim request notification via email. - - Admin initiates transfer via frontend with admin wallet. Frontend requests transaction signing from admin. - - Admin signs transfer transaction (from contract storage to user wallet). Frontend sends the signed transaction to token contract. - - System updates database with claim completion timestamp, destination wallet, and transaction signature. - - Confirmation email is sent to the claimant. - -6. **Auditing & Reporting** - - Dashboard surfaces mint/claim status, IPFS hashes, and notification delivery logs. - - Scheduled jobs reconcile on-chain state with database records. + badge_categories { + UUID id PK + VARCHAR name + TEXT description + TIMESTAMP created_at + } + + badges { + UUID id PK + UUID category_id FK + VARCHAR name + TEXT description + BYTEA image + INTEGER badge_type + INTEGER contract_token_id + TEXT metadata_uri + TIMESTAMP created_at + } + + badge_issuances { + UUID id PK + UUID badge_id FK + UUID user_id FK + UUID issued_by FK + TEXT metadata_uri + INTEGER status + VARCHAR wallet_address + TIMESTAMP created_at + TIMESTAMP updated_at + } + + badge_notifications { + UUID id PK + UUID issuance_id FK + BOOLEAN is_read + TIMESTAMP appeared_at + } + + claim_intents { + UUID id PK + UUID issuance_id FK + INTEGER status + VARCHAR wallet_address + TIMESTAMP submitted_at + TIMESTAMP admin_response_at + } + + badge_logs { + UUID id PK + INTEGER action_type + VARCHAR entity_type + UUID badge_id FK + UUID category_id FK + UUID issuance_id FK + UUID user_id FK + UUID claim_id FK + UUID performed_by FK + VARCHAR blockchain_tx_signature + VARCHAR wallet_address + TEXT old_value + TEXT new_value + INTEGER status + TEXT error_message + TIMESTAMP created_at + } + + email_logs { + UUID id PK + UUID issuance_id FK + INTEGER notification_type + VARCHAR mail_provider_id + VARCHAR status + JSONB metadata + TIMESTAMP created_at + } + + %% Relationships + badge_categories ||--o{ badges : "has" + badges ||--o{ badge_issuances : "issued_as" + users ||--o{ badge_issuances : "receives" + users ||--o{ badge_issuances : "issues" + badge_issuances ||--o{ badge_notifications : "triggers" + badge_issuances ||--o{ claim_intents : "claimed_via" + badge_issuances ||--o{ email_logs : "notified_via" + users ||--o{ badge_logs : "performed_by" + badges ||--o{ badge_logs : "logged" + badge_categories ||--o{ badge_logs : "logged" + badge_issuances ||--o{ badge_logs : "logged" + users ||--o{ badge_logs : "logged" + claim_intents ||--o{ badge_logs : "logged" +``` + +**Note on `wallet_address` in `users` table**: The `wallet_address` field in the `users` table is used to support batch minting operations by admins. When an admin executes a batch-mint action, it would be impossible to manually input all wallet addresses for each recipient. Therefore, users who have a wallet address should set it in their profile page. If a user has not set their wallet address, their badge tokens are automatically minted to the token contract (vault functionality) instead of directly to their wallet, requiring them to claim the badge later. + +--- + +## Appendix + +The following appendix provides illustrative sample data for every column in the database schema. These examples demonstrate the expected data types, formats, and values for each table in the system, serving as a reference for implementation and testing. + +--- + +## Appendix A: Database Schema Sample Data + +Illustrative values for every column in the schema. + +### `users` +| Column | Sample | +| --- | --- | +| `id` | `8f7c7d9b-1c0d-49f1-a29c-03d0c4c2c111` | +| `email` | `alice@example.com` | +| `wallet_address` | `0x32ffw32....3f2` | +| `created_at` | `2025-02-01T10:12:55Z` | +| `updated_at` | `2025-02-10T08:00:00Z` | + + +### `badge_categories` +| Column | Sample | +| --- | --- | +| `id` | `2fcb0271-6316-4c45-9375-8fca4c98840c` | +| `name` | `Contribution Badges` | +| `description` | `GitHub activity milestones` | +| `created_at` | `2025-02-01T09:00:00Z` | + +### `badges` +| Column | Sample | +| --- | --- | +| `id` | `0b1222b9-fd3f-4c4c-8e20-04a0670a74c2` | +| `category_id` | `2fcb0271-6316-4c45-9375-8fca4c98840c` | +| `name` | `SolDev Mentor` | +| `description` | `Mentored five Solana-focused Boost contributors` | +| `image` | `image data (this field may be blob, so the image data can be saved in database.)` | +| `badge_type` | `1 (database-only:0, blockchain:1)` | +| `contract_token_id` | `0 (database-only:null, blockchain:token_id)` | +| `metadata_uri` | `ipfs://Qm...abc/23fwefsdcwcf.json` | +| `created_at` | `2025-02-03T12:05:10Z` | + +### `badge_issuances` +| Column | Sample | +| --- | --- | +| `id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a` | +| `badge_id` | `0b1222b9-fd3f-4c4c-8e20-04a0670a74c2` | +| `user_id` | `8f7c7d9b-1c0d-49f1-a29c-03d0c4c2c111` | +| `metadata_uri` | `ipfs://Qm...abc/sw323edwswef42.json (this value is for only this issuance and updated from IPFS after issuance)` | +| `status` | `0 (pending:0, issued:1, claimed:2) Note: For database-only badges, status 1 (issued) is not used. Status transitions directly from 0 (pending) to 2 (claimed), as 'issued' and 'claimed' are equivalent for database-only badges.` | +| `wallet_address` | `0x32ffw32....3f2` | +| `issued_by` | `4783355a-4095-4fe8-a601-7d61d272af24` | +| `created_at` | `2025-02-05T16:20:00Z` | +| `updated_at` | `2025-02-05T16:20:00Z` | + + +### `badge_notifications` +| Column | Sample | +| --- | --- | +| `id` | `a8bcb904-6de7-4c49-96f9-9b0c165f08f1` | +| `issuance_id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a` | +| `is_read` | `false` | +| `appeared_at` | `2025-02-05T16:25:00Z` | + +### `claim_intents` +| Column | Sample | +| --- | --- | +| `id` | `6d42dc09-1a7f-4cd5-8f24-71e2fc7df7c8` | +| `issuance_id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a` | +| `status` | `0 (pending:0, transferred:1)` | +| `wallet_address` | `0x32ffw32....3f2` | +| `submitted_at` | `2025-02-06T09:30:00Z` | +| `admin_response_at` | `null` | + +### `badge_logs` +| Column | Sample | +| --- | --- | +| `id` | `3232ff1-f23f-32f23-23f2f-23f23f23f23` | +| `action_type` | `0 (badge_created:0, badge_category_created:1, badge_issued:2, badge_claimed:3, wallet_updated:4)` | +| `entity_type` | `issuance (badge, badge_category, issuance, user, claim_intent)` | +| `badge_id` | `0b1222b9-fd3f-4c4c-8e20-04a0670a74c2 (nullable, for badge-related operations)` | +| `category_id` | `2fcb0271-6316-4c45-9375-8fca4c98840c (nullable, for category-related operations)` | +| `issuance_id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a (nullable, for issuance-related operations)` | +| `user_id` | `8f7c7d9b-1c0d-49f1-a29c-03d0c4c2c111 (nullable, for user-related operations)` | +| `claim_id` | `6d42dc09-1a7f-4cd5-8f24-71e2fc7df7c8 (nullable, for claim-related operations)` | +| `performed_by` | `4783355a-4095-4fe8-a601-7d61d272af24 (admin/user who performed the action)` | +| `blockchain_tx_signature` | `5HgZQ...sd8 (nullable, only for blockchain operations)` | +| `wallet_address` | `0xef23rg23f...f23f (nullable, for wallet-related operations)` | +| `old_value` | `null (or previous value for updates, e.g., old wallet address)` | +| `new_value` | `null (or new value for updates, e.g., new wallet address)` | +| `status` | `0 (success:0, failed:1, pending:2)` | +| `error_message` | `null (or error details if status is failed)` | +| `created_at` | `2025-02-05T16:21:00Z` | + + +### `email_logs` +| Column | Sample | +| --- | --- | +| `id` | `ddf95ffa-3236-4413-be0a-09964fa7150d` | +| `issuance_id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a` | +| `notification_type` | `0 (issued_and_claimed:0 - badge sent to wallet for blockchain-based, or issued for database-only, only_issued:1 - badge stored in contract vault, awaiting claim for blockchain-based only)` | +| `mail_provider_id` | `mailman-msg-49811` | +| `status` | `sent` | +| `metadata` | `{"template":"contract-claim","attempt":1}` | +| `created_at` | `2025-02-05T16:26:00Z` | --- + + From 22385ab3914bd18384b7e5dd6d9d104ceefc7c6b Mon Sep 17 00:00:00 2001 From: iTinkerBell Date: Mon, 24 Nov 2025 14:51:00 -0500 Subject: [PATCH 3/4] Draft #3 addressing Dave's comments --- Badging System/Badging NFT Workflow.md | 215 +++++-------------------- 1 file changed, 43 insertions(+), 172 deletions(-) diff --git a/Badging System/Badging NFT Workflow.md b/Badging System/Badging NFT Workflow.md index 326097c..0928af5 100644 --- a/Badging System/Badging NFT Workflow.md +++ b/Badging System/Badging NFT Workflow.md @@ -2,12 +2,9 @@ ## Overview -Refined Solana-based badging flow that supports two badge types: - -- **Blockchain-backed badges** – minted to wallets or stored inside the token contract until claimed. -- **Database-only badges** – managed purely inside the application database with no blockchain touchpoints or wallet requirement. - -Both types share the same metadata and notification pipeline. The implementation window is estimated at three weeks. +Solana-based badges are either +- minted to user wallets (claimed) or +- stored inside the token contract (unclaimed) until claimed. --- @@ -16,37 +13,32 @@ Both types share the same metadata and notification pipeline. The implementation ### Admin 1. **Preparation** - - Admin retrieves token catalogue and recipient roster after metric evaluation via frontend. + - Admin retrieves token catalogue and recipient roster after metric evaluation via Admin UI (Django). - Admin selects badge set (single or batch) and recipients. 2. **Metadata & Persistence** - - Admin submits badge issuance payload to the IPFS service via frontend. + - Admin submits badge issuance payload to the IPFS service via Admin UI (Django). - IPFS returns content URI plus derived metadata (hash, gateway URL). - Application persists issuance record in the database, including user data, claim eligibility flags, and URI references. -3. **Minting / Issuance** - - **Blockchain-backed badges** - - Admin initiates mint via frontend with admin wallet. Frontend requests transaction signing from admin. +3. **Minting / Issuance of Blockchain-backed badges** + - Admin initiates mint in Admin UI (Django). Browser dApp flow requests transaction signing from the admin's wallet plugin. - Admin signs mint or batch mint transaction (supplying recipient wallet if available, token IDs, and metadata URI). - - Frontend sends the signed transaction to the token contract. + - Browser dApp flow submits the signed transaction to the token contract. - Token contract (with built-in vault functionality) validates call and mints tokens: - If wallet provided: Routes tokens directly to user wallets. - If no wallet provided: Stores tokens in the contract's internal storage (vault functionality). - Token contract emits confirmation event with transaction signatures to the database. - Post-confirmation hook triggers notification payload to mailing service (indicating whether badge was sent to wallet or stored in contract). - Mailing service sends email to user (no clickable links; instead prompt them to log into boost.org): - - Direct wallet recipients – badge details and blockchain links. - - Contract-stored recipients – claim instructions, emphasizing security posture. - - **Database-only badges** - - Application marks the issuance as "database-only" and stores the badge entirely in the database (no wallet required). - - Database generates database-only badge notification and triggers mailing service. - - Mailing service sends badge email to user. - -4. **Claim Processing (Blockchain-backed / Contract-Stored Only)** + - Claimed-token recipients – badge details including mint transaction ID. + - Unclaimed-token recipients – claim instructions, emphasizing security posture. + +4. **Claim Processing (Unclaimed Tokens Only)** - Admin receives webhook notification when user submits a claim request. - - Admin initiates transfer via frontend with admin wallet. Frontend requests transaction signing (from contract to wallet). + - Admin initiates transfer in Admin UI (Django). Browser dApp flow requests transaction signing (from contract to wallet). - Admin signs transfer transaction. - - Frontend sends the signed transfer transaction to the token contract. + - Browser dApp flow submits the signed transfer transaction to the token contract. - Token contract delivers the claimed badge to the user wallet. - System records claim completion in the database (transaction signature, wallet, timestamp). - Mailing service sends claim confirmation email to the user. @@ -59,28 +51,17 @@ Both types share the same metadata and notification pipeline. The implementation ### User -1. **Receiving Badge Notifications** - - User receives email notification about badge issuance (no clickable links, instead prompt them to log into boost.org): - - **Blockchain-backed badges (direct wallet)**: Email contains badge details. - - **Blockchain-backed badges (contract-stored)**: Email contains claim instructions. - - **Database-only badges**: Email contains badge details. - -2. **Viewing Badge Notifications (Database-only Badges)** - - User logs into the frontend. - - User views badge notification history. - - User can view database-only badges without wallet submission or admin transfer. - -3. **Claiming Badges (Blockchain-backed / Contract-Stored Only)** - - User logs into the frontend and views pending claim notifications. - - Frontend requests pending contract-stored badges from the claim service. - - Claim service queries the database for pending badge notifications and returns selectable notifications to the frontend. + +**Claiming Badges (Unclaimed Tokens Only)** + - User logs into the User Web App and views unclaimed blockchain-backed badges. + - User Web App requests pending unclaimed tokens from the claim service. + - Claim service queries the database for pending badge notifications and returns selectable notifications to the User Web App. - User selects one or more badges and provides wallet address(es) (one wallet can be used for multiple badges, or separate wallets for each badge), then submits the claim request. - - Frontend sends the claim selection (URI, token ID, wallet) to the claim service. + - User Web App sends the claim selection (URI, token ID, wallet) to the claim service. - Claim service updates the database with claim intent details (URI, token ID, wallet, timestamp). - Claim service sends claim request payload (URI, token ID, wallet) to admin webhook. - User waits for admin to process the claim request. - User receives claim confirmation email once the badge is transferred to their wallet. - - **Note**: Database-only badges skip this section entirely – users already "own" the badge in the portal and can view without wallet submission or admin transfer. --- @@ -89,7 +70,8 @@ Both types share the same metadata and notification pipeline. The implementation ```mermaid sequenceDiagram autonumber - participant FE as Frontend + participant AdminUI as Admin UI (Django) + participant UserApp as User Web App (browser) participant IPFS as IPFS Service participant DB as Database participant Admin as Admin Wallet @@ -100,14 +82,14 @@ sequenceDiagram participant Claim as Claim Service participant Wallet as User Wallet - FE->>IPFS: Submit user + badge payload - IPFS-->>FE: Return URI + CID metadata - FE->>DB: Persist issuance record (user data, URI, flags) + AdminUI->>IPFS: Submit user + badge payload + IPFS-->>AdminUI: Return URI + CID metadata + AdminUI->>DB: Persist issuance record (user data, URI, flags) alt Blockchain-backed badge - Admin->>FE: Initiate mint (via frontend with admin wallet) - FE->>Admin: Request transaction signing (token IDs, URI, wallet) - Admin->>FE: Sign mint or batch mint transaction - FE->>Sol: Send mint transaction + Admin->>AdminUI: Initiate mint (via Admin UI with admin wallet) + AdminUI->>Admin: Request transaction signing (token IDs, URI, wallet) + Admin->>AdminUI: Sign mint or batch mint transaction + AdminUI->>Sol: Send mint transaction Sol-->>Wallet: Mint badge to user wallet (if provided) Sol-->>Sol: Store badge in contract (no wallet address) Sol-->>DB: Emit confirmation event (tx signatures) @@ -115,29 +97,29 @@ sequenceDiagram Sol-->>Mail: Trigger notification payload (wallet vs stored in contract) Mail-->>User: Send email (direct badge info or claim instructions) - Note over Claim,DB: Claim service queries DB for contract-stored badges
and associated recipient metadata + Note over Claim,DB: Claim service queries DB for unclaimed tokens
and associated recipient metadata - User->>FE: Login & view claim notifications - FE->>Claim: Request pending contract-stored badges + User->>UserApp: Login & view claim notifications + UserApp->>Claim: Request pending unclaimed tokens Claim->>DB: Query pending badge notifications - Claim-->>FE: Return selectable notifications - User->>FE: Select badges - FE->>Claim: Submit claim selection (URI, token ID, wallet) with wallet address(es) + Claim-->>UserApp: Return selectable notifications + User->>UserApp: Select badges + UserApp->>Claim: Submit claim selection (URI, token ID, wallet) with wallet address(es) Claim->>DB: Update claim intent, log timestamp Claim->>Hook: Send claim request payload (URI, token ID, wallet) Hook-->>Admin: Notify admin via webhook - Admin->>FE: Initiate transfer (via frontend with admin wallet) - FE->>Admin: Request transaction signing (from contract to wallet) - Admin->>FE: Sign transfer transaction - FE->>Sol: Send transfer transaction + Admin->>AdminUI: Initiate transfer (via Admin UI with admin wallet) + AdminUI->>Admin: Request transaction signing (from contract to wallet) + Admin->>AdminUI: Sign transfer transaction + AdminUI->>Sol: Send transfer transaction Sol-->>Wallet: Deliver claimed badge to user wallet Sol-->>DB: Record claim completion (tx signature, wallet) Mail-->>User: Send claim confirmation email else Database-only badge - DB->>Mail: Generate database-only badge notification - Mail-->>User: Send badge email (no wallet required) - User->>FE: View badge notification history - Note over DB: Database tracks issuance, views, and acknowledgements
without blockchain transactions + User->>UserApp: View badges in profile (no wallet required) + UserApp->>DB: Query database-only badges + DB-->>UserApp: Return badges + Note over DB: Database tracks issuance, views, and acknowledgements
without blockchain transactions or emails end Note over DB: Maintain full lifecycle history
(metadata hash, issuance, claim selections, completion) @@ -250,114 +232,3 @@ erDiagram ``` **Note on `wallet_address` in `users` table**: The `wallet_address` field in the `users` table is used to support batch minting operations by admins. When an admin executes a batch-mint action, it would be impossible to manually input all wallet addresses for each recipient. Therefore, users who have a wallet address should set it in their profile page. If a user has not set their wallet address, their badge tokens are automatically minted to the token contract (vault functionality) instead of directly to their wallet, requiring them to claim the badge later. - ---- - -## Appendix - -The following appendix provides illustrative sample data for every column in the database schema. These examples demonstrate the expected data types, formats, and values for each table in the system, serving as a reference for implementation and testing. - ---- - -## Appendix A: Database Schema Sample Data - -Illustrative values for every column in the schema. - -### `users` -| Column | Sample | -| --- | --- | -| `id` | `8f7c7d9b-1c0d-49f1-a29c-03d0c4c2c111` | -| `email` | `alice@example.com` | -| `wallet_address` | `0x32ffw32....3f2` | -| `created_at` | `2025-02-01T10:12:55Z` | -| `updated_at` | `2025-02-10T08:00:00Z` | - - -### `badge_categories` -| Column | Sample | -| --- | --- | -| `id` | `2fcb0271-6316-4c45-9375-8fca4c98840c` | -| `name` | `Contribution Badges` | -| `description` | `GitHub activity milestones` | -| `created_at` | `2025-02-01T09:00:00Z` | - -### `badges` -| Column | Sample | -| --- | --- | -| `id` | `0b1222b9-fd3f-4c4c-8e20-04a0670a74c2` | -| `category_id` | `2fcb0271-6316-4c45-9375-8fca4c98840c` | -| `name` | `SolDev Mentor` | -| `description` | `Mentored five Solana-focused Boost contributors` | -| `image` | `image data (this field may be blob, so the image data can be saved in database.)` | -| `badge_type` | `1 (database-only:0, blockchain:1)` | -| `contract_token_id` | `0 (database-only:null, blockchain:token_id)` | -| `metadata_uri` | `ipfs://Qm...abc/23fwefsdcwcf.json` | -| `created_at` | `2025-02-03T12:05:10Z` | - -### `badge_issuances` -| Column | Sample | -| --- | --- | -| `id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a` | -| `badge_id` | `0b1222b9-fd3f-4c4c-8e20-04a0670a74c2` | -| `user_id` | `8f7c7d9b-1c0d-49f1-a29c-03d0c4c2c111` | -| `metadata_uri` | `ipfs://Qm...abc/sw323edwswef42.json (this value is for only this issuance and updated from IPFS after issuance)` | -| `status` | `0 (pending:0, issued:1, claimed:2) Note: For database-only badges, status 1 (issued) is not used. Status transitions directly from 0 (pending) to 2 (claimed), as 'issued' and 'claimed' are equivalent for database-only badges.` | -| `wallet_address` | `0x32ffw32....3f2` | -| `issued_by` | `4783355a-4095-4fe8-a601-7d61d272af24` | -| `created_at` | `2025-02-05T16:20:00Z` | -| `updated_at` | `2025-02-05T16:20:00Z` | - - -### `badge_notifications` -| Column | Sample | -| --- | --- | -| `id` | `a8bcb904-6de7-4c49-96f9-9b0c165f08f1` | -| `issuance_id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a` | -| `is_read` | `false` | -| `appeared_at` | `2025-02-05T16:25:00Z` | - -### `claim_intents` -| Column | Sample | -| --- | --- | -| `id` | `6d42dc09-1a7f-4cd5-8f24-71e2fc7df7c8` | -| `issuance_id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a` | -| `status` | `0 (pending:0, transferred:1)` | -| `wallet_address` | `0x32ffw32....3f2` | -| `submitted_at` | `2025-02-06T09:30:00Z` | -| `admin_response_at` | `null` | - -### `badge_logs` -| Column | Sample | -| --- | --- | -| `id` | `3232ff1-f23f-32f23-23f2f-23f23f23f23` | -| `action_type` | `0 (badge_created:0, badge_category_created:1, badge_issued:2, badge_claimed:3, wallet_updated:4)` | -| `entity_type` | `issuance (badge, badge_category, issuance, user, claim_intent)` | -| `badge_id` | `0b1222b9-fd3f-4c4c-8e20-04a0670a74c2 (nullable, for badge-related operations)` | -| `category_id` | `2fcb0271-6316-4c45-9375-8fca4c98840c (nullable, for category-related operations)` | -| `issuance_id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a (nullable, for issuance-related operations)` | -| `user_id` | `8f7c7d9b-1c0d-49f1-a29c-03d0c4c2c111 (nullable, for user-related operations)` | -| `claim_id` | `6d42dc09-1a7f-4cd5-8f24-71e2fc7df7c8 (nullable, for claim-related operations)` | -| `performed_by` | `4783355a-4095-4fe8-a601-7d61d272af24 (admin/user who performed the action)` | -| `blockchain_tx_signature` | `5HgZQ...sd8 (nullable, only for blockchain operations)` | -| `wallet_address` | `0xef23rg23f...f23f (nullable, for wallet-related operations)` | -| `old_value` | `null (or previous value for updates, e.g., old wallet address)` | -| `new_value` | `null (or new value for updates, e.g., new wallet address)` | -| `status` | `0 (success:0, failed:1, pending:2)` | -| `error_message` | `null (or error details if status is failed)` | -| `created_at` | `2025-02-05T16:21:00Z` | - - -### `email_logs` -| Column | Sample | -| --- | --- | -| `id` | `ddf95ffa-3236-4413-be0a-09964fa7150d` | -| `issuance_id` | `3bf34c2a-3bb0-47cb-9336-6a9c8f4ecb5a` | -| `notification_type` | `0 (issued_and_claimed:0 - badge sent to wallet for blockchain-based, or issued for database-only, only_issued:1 - badge stored in contract vault, awaiting claim for blockchain-based only)` | -| `mail_provider_id` | `mailman-msg-49811` | -| `status` | `sent` | -| `metadata` | `{"template":"contract-claim","attempt":1}` | -| `created_at` | `2025-02-05T16:26:00Z` | - ---- - - From 2aad8f10892854ca62e8c04066c9e9a22ff25249 Mon Sep 17 00:00:00 2001 From: iTinkerBell Date: Tue, 25 Nov 2025 18:24:58 -0500 Subject: [PATCH 4/4] Addressing comments --- Badging System/Badging NFT Workflow.md | 31 ++++++++++++++++---------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Badging System/Badging NFT Workflow.md b/Badging System/Badging NFT Workflow.md index 0928af5..16e3180 100644 --- a/Badging System/Badging NFT Workflow.md +++ b/Badging System/Badging NFT Workflow.md @@ -53,13 +53,13 @@ Solana-based badges are either **Claiming Badges (Unclaimed Tokens Only)** - - User logs into the User Web App and views unclaimed blockchain-backed badges. - - User Web App requests pending unclaimed tokens from the claim service. - - Claim service queries the database for pending badge notifications and returns selectable notifications to the User Web App. - - User selects one or more badges and provides wallet address(es) (one wallet can be used for multiple badges, or separate wallets for each badge), then submits the claim request. - - User Web App sends the claim selection (URI, token ID, wallet) to the claim service. - - Claim service updates the database with claim intent details (URI, token ID, wallet, timestamp). - - Claim service sends claim request payload (URI, token ID, wallet) to admin webhook. + - User logs into the User Web App. + - If the user has unclaimed blockchain-backed badges and no wallet address on file, the User Web App notifies them that they have unclaimed badges and guides them to create a wallet (if needed) and set a primary wallet address in their user profile. + - Once a wallet address is set in the user profile, the User Web App displays the user's unclaimed blockchain-backed badges. + - User selects one or more badges and submits the claim request (no per-claim wallet entry; the profile wallet is used). + - User Web App sends the claim selection (URI, token ID) together with the user's profile `wallet_address` to the claim service. + - Claim service updates the database with claim intent details (URI, token ID, wallet_address, timestamp). + - Claim service sends claim request payload (URI, token ID, wallet_address) to the admin webhook. - User waits for admin to process the claim request. - User receives claim confirmation email once the badge is transferred to their wallet. @@ -99,14 +99,21 @@ sequenceDiagram Note over Claim,DB: Claim service queries DB for unclaimed tokens
and associated recipient metadata - User->>UserApp: Login & view claim notifications - UserApp->>Claim: Request pending unclaimed tokens + User->>UserApp: Login + UserApp->>DB: Check for unclaimed badges and wallet on file + DB-->>UserApp: Return unclaimed badges + wallet_on_file flag + UserApp-->>User: If no wallet on file, prompt to add wallet address in profile + User->>UserApp: Set or confirm profile wallet address + UserApp->>DB: Persist `wallet_address` on user + + User->>UserApp: View claim notifications + UserApp->>Claim: Request pending unclaimed tokens (for user with wallet on file) Claim->>DB: Query pending badge notifications Claim-->>UserApp: Return selectable notifications User->>UserApp: Select badges - UserApp->>Claim: Submit claim selection (URI, token ID, wallet) with wallet address(es) + UserApp->>Claim: Submit claim selection (URI, token ID, wallet_from_profile) Claim->>DB: Update claim intent, log timestamp - Claim->>Hook: Send claim request payload (URI, token ID, wallet) + Claim->>Hook: Send claim request payload (URI, token ID, wallet_from_profile) Hook-->>Admin: Notify admin via webhook Admin->>AdminUI: Initiate transfer (via Admin UI with admin wallet) AdminUI->>Admin: Request transaction signing (from contract to wallet) @@ -231,4 +238,4 @@ erDiagram claim_intents ||--o{ badge_logs : "logged" ``` -**Note on `wallet_address` in `users` table**: The `wallet_address` field in the `users` table is used to support batch minting operations by admins. When an admin executes a batch-mint action, it would be impossible to manually input all wallet addresses for each recipient. Therefore, users who have a wallet address should set it in their profile page. If a user has not set their wallet address, their badge tokens are automatically minted to the token contract (vault functionality) instead of directly to their wallet, requiring them to claim the badge later. +**Note on `wallet_address` in `users` table**: The `wallet_address` field in the `users` table is used both to support batch minting operations by admins and to drive the user-initiated claim flow. When an admin executes a batch-mint action, it would be impossible to manually input all wallet addresses for each recipient. Therefore, users who have a wallet address should set it in their profile page. If a user has not set their wallet address, their badge tokens are automatically minted to the token contract (vault functionality) instead of directly to their wallet, requiring them to claim the badge later. When a user later claims an unclaimed badge, the system uses the `wallet_address` stored on the user profile (rather than letting the user enter multiple arbitrary wallets per claim).