Skip to content

Equipment CRUD Workflow

GaveKort MultiTenant - Wallet Items Management

Equipment in this system refers to Wallet Items (Giftcards, Range Tokens, Greenfee Tickets).

graph TD
    Start([Admin/Staff Initiates]) --> CheckAuth{Check<br/>Authorization}

    CheckAuth -->|Not Authorized| Error1["❌ Permission Denied<br/>HTTP 403"]
    CheckAuth -->|Authorized| ChooseOp{Select<br/>Operation}

    %% CREATE/ISSUE PATH
    ChooseOp -->|Issue New| Issue["📝 Issue Equipment<br/>- Form: Product + User + ClaimCode"]
    Issue --> Validate1["✓ Validate Input<br/>- productId exists?<br/>- idempotencyKey unique?"]
    Validate1 -->|Invalid| Error2["❌ Validation Error<br/>Return 400"]
    Validate1 -->|Valid| Lock["🔒 Acquire Idempotency Lock<br/>idempotency_keys collection"]
    Lock --> CreateWallet["📦 Create Wallet Item<br/>- walletItemId (UUID)<br/>- userId, type, value<br/>- status: ACTIVE<br/>- issuedBy, issuedAt"]
    CreateWallet --> CreateLedger1["📋 Create Ledger Transaction<br/>- type: ISSUE<br/>- amount: product.value<br/>- reference: walletItemId"]
    CreateLedger1 --> UpdateProjection1["📊 Update Wallet Projection<br/>Recalculate user balance"]
    UpdateProjection1 --> CompleteIdempotency1["✅ Mark Idempotency Complete<br/>Store response result"]
    CompleteIdempotency1 --> Response1["✓ Return walletItemId<br/>+ ledgerTxId"]

    %% EDIT PATH
    ChooseOp -->|Edit Item| Edit["✏️ Edit Equipment<br/>- Lookup by walletItemId<br/>- Allow: value, expiresAt, claimCode"]
    Edit --> CheckStatus["⚠️ Check Item Status<br/>- ACTIVE? OK<br/>- REDEEMED/EXPIRED? Blocked"]
    CheckStatus -->|Invalid Status| Error3["❌ Cannot Edit<br/>Item Already Used"]
    CheckStatus -->|Valid| Validate2["✓ Validate Changes<br/>- Prevent reducing value<br/>below used amount"]
    Validate2 -->|Invalid| Error4["❌ Invalid Change<br/>Used amount exceeded"]
    Validate2 -->|Valid| UpdateWallet["♻️ Update Wallet Item<br/>- Modify fields<br/>- Set updatedAt"]
    UpdateWallet --> CreateLedger2["📋 Create Ledger Transaction<br/>- type: ADJUST/MODIFY<br/>- Record what changed<br/>- Audit trail"]
    CreateLedger2 --> UpdateProjection2["📊 Update Wallet Projection<br/>Recalculate if value changed"]
    UpdateProjection2 --> Response2["✓ Return Updated Item"]

    %% DELETE/REVOKE PATH
    ChooseOp -->|Delete/Revoke| Delete["🗑️ Delete Equipment<br/>- Lookup by walletItemId<br/>- Request reason"]
    Delete --> CheckStatus2["⚠️ Check Item Status<br/>- ACTIVE? OK<br/>- REDEEMED/EXPIRED? Already Gone"]
    CheckStatus2 -->|Invalid| Error5["❌ Cannot Delete<br/>Item Already Used"]
    CheckStatus2 -->|Valid| Confirm["🔍 Require Confirmation<br/>- Admin confirms deletion<br/>- Reason recorded"]
    Confirm --> SetStatus["⛔ Mark as BLOCKED<br/>status: BLOCKED<br/>Soft delete for audit trail"]
    SetStatus --> CreateLedger3["📋 Create Ledger Transaction<br/>- type: BLOCK<br/>- reason: [admin reason]<br/>- refund: if partially used"]
    CreateLedger3 --> UpdateProjection3["📊 Update Wallet Projection<br/>Remove from active balance"]
    UpdateProjection3 --> AuditLog["📝 Add Admin Audit Log<br/>- Action: DELETE_EQUIPMENT<br/>- Admin ID, timestamp, reason"]
    AuditLog --> Response3["✓ Deletion Confirmed<br/>Item marked as BLOCKED"]

    %% SUCCESS PATHS
    Response1 --> Success["✅ OPERATION COMPLETE"]
    Response2 --> Success
    Response3 --> Success
    Error1 --> Fail["❌ OPERATION FAILED"]
    Error2 --> Fail
    Error3 --> Fail
    Error4 --> Fail
    Error5 --> Fail

    style Start fill:#e1f5ff
    style Success fill:#c8e6c9
    style Fail fill:#ffcdd2
    style Lock fill:#fff3e0
    style CreateWallet fill:#f3e5f5
    style CreateLedger1 fill:#f3e5f5
    style CreateLedger2 fill:#f3e5f5
    style CreateLedger3 fill:#f3e5f5
    style UpdateProjection1 fill:#e0f2f1
    style UpdateProjection2 fill:#e0f2f1
    style UpdateProjection3 fill:#e0f2f1

Process Details

CREATE (ISSUE)

  • Initiator: Admin/Staff user
  • Entry Point: issueGiftCard() callable function
  • Data Created:
  • wallet_items/{walletItemId} - Equipment record
  • ledger_transactions/{txId} - ISSUE transaction
  • wallet_projections/{userId} - Balance updated
  • Idempotency: Full protection via idempotencyKey
  • Audit: Tracked in ledger (issuedBy, issuedAt)

EDIT (MODIFY)

  • Allowed Changes: value, expiresAt, claimCode (if not yet claimed)
  • Status Restrictions: Only ACTIVE items can be edited
  • Validation: Cannot reduce value below usedAmount
  • Ledger: Creates ADJUST transaction for changes
  • Audit: updatedAt timestamp and ledger entry

DELETE (BLOCK/REVOKE)

  • Method: Soft delete (status → BLOCKED)
  • Reason: Maintains audit trail
  • Restrictions: Can only block ACTIVE items
  • Refund Logic: If partially used, creates REFUND transaction
  • Audit Log: Full admin action logged in admin_audit_log
  • Timestamp: Immutable deletion record

Data Integrity Rules

  1. ✅ Cannot edit REDEEMED or EXPIRED items
  2. ✅ Cannot reduce value below usedAmount
  3. ✅ Every operation creates ledger entry
  4. ✅ Idempotency prevents duplicate operations
  5. ✅ Projections auto-recalculated after each change