1019 lines
27 KiB
Markdown
1019 lines
27 KiB
Markdown
|
|
# Goa GEL Blockchain Document Verification Platform - Architecture Guide
|
||
|
|
|
||
|
|
## Executive Summary
|
||
|
|
|
||
|
|
The Goa Government E-License (GEL) Blockchain Document Verification Platform is a comprehensive solution for managing government licenses and permits through a multi-department approval workflow backed by blockchain technology. The platform leverages Hyperledger Besu with QBFT consensus to ensure tamper-proof records of license issuance.
|
||
|
|
|
||
|
|
**Key Innovation**: Multi-department approval workflows with immutable blockchain records and soulbound NFT certificates.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. System Context (C4 Level 1)
|
||
|
|
|
||
|
|
### Overview
|
||
|
|
The GEL platform serves as the central integration point for government entities, citizens, and external systems.
|
||
|
|
|
||
|
|
### Actors & Systems
|
||
|
|
|
||
|
|
#### External Actors
|
||
|
|
- **Citizens**: Submit license requests, upload documents, track approval status
|
||
|
|
- **Government Departments**: Configure workflows, review and approve requests
|
||
|
|
- **Department Operators**: Manage department users and approval rules
|
||
|
|
- **Platform Operators**: System administration, monitoring, maintenance
|
||
|
|
|
||
|
|
#### External Systems
|
||
|
|
- **DigiLocker Mock**: Verifies document authenticity (POC implementation)
|
||
|
|
- **Legacy Department Systems**: Integration for existing government databases
|
||
|
|
- **National Blockchain Federation**: Future interoperability with national systems
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Container Architecture (C4 Level 2)
|
||
|
|
|
||
|
|
### Layered Architecture
|
||
|
|
|
||
|
|
#### Frontend Layer
|
||
|
|
```
|
||
|
|
Next.js 14 + shadcn/ui
|
||
|
|
├── Pages: Dashboard, License Requests, Approvals
|
||
|
|
├── Components: Forms, Document Upload, Status Tracking
|
||
|
|
├── State: React Context + TanStack Query
|
||
|
|
└── Styling: Tailwind CSS (dark theme optimized)
|
||
|
|
Port: 3000
|
||
|
|
```
|
||
|
|
|
||
|
|
#### API & Backend Layer
|
||
|
|
```
|
||
|
|
NestJS TypeScript API Gateway (Port 3001)
|
||
|
|
├── Auth Service (API Key + Secret POC)
|
||
|
|
├── Workflow Service
|
||
|
|
├── Approval Service
|
||
|
|
├── Document Service
|
||
|
|
└── Blockchain Integration Module
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Data Layer
|
||
|
|
```
|
||
|
|
PostgreSQL Database (Port 5432)
|
||
|
|
├── license_requests table
|
||
|
|
├── approvals table
|
||
|
|
├── documents table
|
||
|
|
├── audit_logs table
|
||
|
|
└── department_registry table
|
||
|
|
|
||
|
|
Redis Cache (Port 6379)
|
||
|
|
├── Session management
|
||
|
|
├── Workflow state cache
|
||
|
|
└── Real-time notifications
|
||
|
|
|
||
|
|
MinIO Object Storage (Port 9000)
|
||
|
|
├── License documents (PDFs)
|
||
|
|
├── Supporting images
|
||
|
|
├── Document proofs
|
||
|
|
└── Generated certificates
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Blockchain Layer
|
||
|
|
```
|
||
|
|
Hyperledger Besu Network (QBFT Consensus)
|
||
|
|
├── 4 Validator Nodes (Ports 8545-8548)
|
||
|
|
├── RPC Endpoints
|
||
|
|
├── Peer-to-Peer Network
|
||
|
|
└── Smart Contracts:
|
||
|
|
├── LicenseRequestNFT (ERC-721 Soulbound)
|
||
|
|
├── ApprovalManager
|
||
|
|
├── DepartmentRegistry
|
||
|
|
└── WorkflowRegistry
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Blockchain Architecture Deep Dive
|
||
|
|
|
||
|
|
### Hyperledger Besu Configuration
|
||
|
|
|
||
|
|
#### Network Topology
|
||
|
|
```
|
||
|
|
4 Validator Nodes (QBFT Consensus)
|
||
|
|
├── Validator 1 (RPC: 8545, P2P: 30303)
|
||
|
|
├── Validator 2 (RPC: 8546, P2P: 30304)
|
||
|
|
├── Validator 3 (RPC: 8547, P2P: 30305)
|
||
|
|
└── Validator 4 (RPC: 8548, P2P: 30306)
|
||
|
|
|
||
|
|
Consensus Rule: Requires 3/4 (75%) validator approval
|
||
|
|
Block Time: ~12 seconds
|
||
|
|
```
|
||
|
|
|
||
|
|
### Smart Contracts
|
||
|
|
|
||
|
|
#### 1. LicenseRequestNFT (ERC-721 Soulbound)
|
||
|
|
```solidity
|
||
|
|
Contract Type: ERC-721 (Non-Fungible Token)
|
||
|
|
Purpose: Issue immutable, non-transferable license certificates
|
||
|
|
|
||
|
|
Key Functions:
|
||
|
|
- mint(applicant, licenseHash, metadataURI, issuerDept)
|
||
|
|
└─ Creates NFT, emits Transfer event
|
||
|
|
- burn(tokenId)
|
||
|
|
└─ Revokes license, removes from circulation
|
||
|
|
- ownerOf(tokenId) → address
|
||
|
|
- tokenURI(tokenId) → string (IPFS or HTTP)
|
||
|
|
|
||
|
|
Soulbound Property:
|
||
|
|
- _beforeTokenTransfer() override prevents transfers
|
||
|
|
- Only issuer can revoke
|
||
|
|
- Applicant owns NFT but cannot sell/transfer
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. ApprovalManager
|
||
|
|
```solidity
|
||
|
|
Purpose: Record and manage multi-department approvals
|
||
|
|
|
||
|
|
Key Functions:
|
||
|
|
- recordApproval(licenseHash, department, signature)
|
||
|
|
└─ Logs approval from specific department
|
||
|
|
- recordRejection(licenseHash, department, reason)
|
||
|
|
└─ Logs rejection with reason
|
||
|
|
- requestChanges(licenseHash, department, details)
|
||
|
|
└─ Request changes from applicant
|
||
|
|
- getApprovalChain(licenseHash) → approvalRecord[]
|
||
|
|
└─ Full approval history
|
||
|
|
|
||
|
|
Data Structures:
|
||
|
|
ApprovalRecord {
|
||
|
|
licenseHash: bytes32,
|
||
|
|
department: address,
|
||
|
|
approvalStatus: enum (PENDING, APPROVED, REJECTED, CHANGES_REQUESTED),
|
||
|
|
timestamp: uint256,
|
||
|
|
notes: string,
|
||
|
|
signature: bytes
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. DepartmentRegistry
|
||
|
|
```solidity
|
||
|
|
Purpose: Maintain department information and approvers
|
||
|
|
|
||
|
|
Key Functions:
|
||
|
|
- registerDepartment(deptId, deptName, metadata)
|
||
|
|
- setApprovers(deptId, approverAddresses[])
|
||
|
|
- getApprovers(deptId) → address[]
|
||
|
|
- isDeptApprover(deptId, address) → bool
|
||
|
|
|
||
|
|
Data Structure:
|
||
|
|
Department {
|
||
|
|
deptId: bytes32,
|
||
|
|
name: string,
|
||
|
|
approvers: address[],
|
||
|
|
isActive: bool,
|
||
|
|
registeredAt: uint256
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4. WorkflowRegistry
|
||
|
|
```solidity
|
||
|
|
Purpose: Define and manage license approval workflows
|
||
|
|
|
||
|
|
Key Functions:
|
||
|
|
- defineWorkflow(workflowId, licenseType, departments[])
|
||
|
|
- getWorkflow(workflowId) → workflowConfig
|
||
|
|
- getNextApprovers(workflowId, currentStep) → address[]
|
||
|
|
|
||
|
|
Data Structure:
|
||
|
|
Workflow {
|
||
|
|
workflowId: bytes32,
|
||
|
|
licenseType: string,
|
||
|
|
departments: Department[],
|
||
|
|
isSequential: bool,
|
||
|
|
timeout: uint256,
|
||
|
|
createdAt: uint256
|
||
|
|
}
|
||
|
|
|
||
|
|
Example: Resort License POC
|
||
|
|
├─ Step 1: Tourism Department Review (Parallel possible)
|
||
|
|
└─ Step 2: Fire Safety Department Review
|
||
|
|
```
|
||
|
|
|
||
|
|
### On-Chain vs Off-Chain Data Split
|
||
|
|
|
||
|
|
#### On-Chain Data (Blockchain State)
|
||
|
|
```
|
||
|
|
Immutable & Transparent
|
||
|
|
├── License Hashes (SHA-256 of documents)
|
||
|
|
├── Approval Records (with signatures)
|
||
|
|
├── Department Registry
|
||
|
|
├── Workflow Definitions
|
||
|
|
└── NFT Ownership Records
|
||
|
|
|
||
|
|
Benefits:
|
||
|
|
- Tamper-proof
|
||
|
|
- Publicly verifiable
|
||
|
|
- Immutable audit trail
|
||
|
|
- Non-repudiation
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Off-Chain Data (PostgreSQL + MinIO)
|
||
|
|
```
|
||
|
|
Flexible & Queryable
|
||
|
|
├── Full License Request Details
|
||
|
|
├── Applicant Information
|
||
|
|
├── Document Metadata
|
||
|
|
├── Workflow State (current step)
|
||
|
|
├── User Comments & Notes
|
||
|
|
├── Audit Logs (indexed queries)
|
||
|
|
└── Actual Document Files (PDFs, images)
|
||
|
|
|
||
|
|
Benefits:
|
||
|
|
- Searchable
|
||
|
|
- Quick queries
|
||
|
|
- Scalable storage
|
||
|
|
- Privacy controls
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Data Linking
|
||
|
|
```
|
||
|
|
SHA-256 Hash: Immutable Bridge Between On-Chain & Off-Chain
|
||
|
|
|
||
|
|
Document File
|
||
|
|
↓ (hash)
|
||
|
|
SHA-256: 0x7f8c...a1b2
|
||
|
|
↓ (stored on-chain)
|
||
|
|
Smart Contract State
|
||
|
|
↓ (referenced in off-chain DB)
|
||
|
|
PostgreSQL record contains this hash
|
||
|
|
↓ (verification)
|
||
|
|
Anyone can hash the document and verify it matches blockchain record
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Workflow State Machine
|
||
|
|
|
||
|
|
### License Request States
|
||
|
|
|
||
|
|
```
|
||
|
|
DRAFT
|
||
|
|
├─ Initial state
|
||
|
|
├─ Applicant can edit
|
||
|
|
├─ No blockchain record
|
||
|
|
└─ Can transition to: SUBMITTED or [abandon]
|
||
|
|
|
||
|
|
↓ [submit for review]
|
||
|
|
|
||
|
|
SUBMITTED
|
||
|
|
├─ Hash recorded on blockchain
|
||
|
|
├─ Locked from editing
|
||
|
|
├─ Routed to appropriate departments
|
||
|
|
└─ Can transition to: IN_REVIEW or [withdraw]
|
||
|
|
|
||
|
|
↓ [route to approvers]
|
||
|
|
|
||
|
|
IN_REVIEW
|
||
|
|
├─ Multi-department approval workflow
|
||
|
|
├─ Can be parallel or sequential
|
||
|
|
├─ Department approvers review documents
|
||
|
|
└─ Can transition to: APPROVED, REJECTED, or PENDING_RESUBMISSION
|
||
|
|
|
||
|
|
├─ [all approve] → APPROVED
|
||
|
|
├─ [any reject] → REJECTED
|
||
|
|
└─ [changes requested] → PENDING_RESUBMISSION
|
||
|
|
|
||
|
|
PENDING_RESUBMISSION
|
||
|
|
├─ Applicant notified of required changes
|
||
|
|
├─ Time-limited window for corrections
|
||
|
|
├─ Can resubmit documents
|
||
|
|
└─ Can transition to: SUBMITTED or [withdraw]
|
||
|
|
|
||
|
|
↓ [resubmit with changes]
|
||
|
|
|
||
|
|
SUBMITTED (again in workflow)
|
||
|
|
↓ [back to IN_REVIEW]
|
||
|
|
|
||
|
|
APPROVED (Final State)
|
||
|
|
├─ All departments approved
|
||
|
|
├─ ERC-721 Soulbound NFT minted
|
||
|
|
├─ License certificate generated
|
||
|
|
├─ Verifiable on blockchain
|
||
|
|
└─ Can transition to: REVOKED only
|
||
|
|
|
||
|
|
↓ [license revoked/expired]
|
||
|
|
|
||
|
|
REVOKED
|
||
|
|
├─ License cancelled
|
||
|
|
├─ NFT burned from circulation
|
||
|
|
├─ Audit trail preserved
|
||
|
|
└─ End state
|
||
|
|
|
||
|
|
REJECTED (Terminal State)
|
||
|
|
├─ Request denied permanently
|
||
|
|
├─ Reason recorded on-chain
|
||
|
|
├─ Applicant can appeal (future feature)
|
||
|
|
└─ Can transition to: DRAFT (reapply)
|
||
|
|
```
|
||
|
|
|
||
|
|
### Approval States (Per Department)
|
||
|
|
|
||
|
|
```
|
||
|
|
PENDING
|
||
|
|
├─ Awaiting department review
|
||
|
|
├─ Notification sent to approvers
|
||
|
|
└─ Can transition to: APPROVED, REJECTED, or CHANGES_REQUESTED
|
||
|
|
|
||
|
|
├─ [approve] → APPROVED
|
||
|
|
├─ [reject] → REJECTED
|
||
|
|
└─ [request changes] → CHANGES_REQUESTED
|
||
|
|
|
||
|
|
APPROVED
|
||
|
|
├─ Department approved this request
|
||
|
|
└─ Recorded on blockchain with signature
|
||
|
|
|
||
|
|
REJECTED
|
||
|
|
├─ Department rejected request
|
||
|
|
├─ Reason recorded
|
||
|
|
└─ Triggers overall REJECTED state
|
||
|
|
|
||
|
|
CHANGES_REQUESTED
|
||
|
|
├─ Department needs clarifications/corrections
|
||
|
|
├─ Specific details provided
|
||
|
|
└─ Applicant must resubmit
|
||
|
|
|
||
|
|
REVIEW_REQUIRED
|
||
|
|
├─ Resubmitted after changes
|
||
|
|
├─ Needs re-review
|
||
|
|
└─ Back to PENDING
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. End-to-End Data Flow
|
||
|
|
|
||
|
|
### 11-Step Resort License Approval Process
|
||
|
|
|
||
|
|
#### Step 1-2: Submission & Upload
|
||
|
|
```
|
||
|
|
1. Citizen creates Resort License request in Next.js frontend
|
||
|
|
2. Fills in applicant information (name, contact, resort details)
|
||
|
|
3. Uploads supporting documents:
|
||
|
|
- Property proof
|
||
|
|
- Health certificate
|
||
|
|
- Fire safety plan
|
||
|
|
- Environmental clearance
|
||
|
|
- etc.
|
||
|
|
|
||
|
|
Frontend sends to NestJS API:
|
||
|
|
POST /licenses/create
|
||
|
|
├── Body: License form data
|
||
|
|
├── Files: Multipart documents
|
||
|
|
└── Auth: API Key header
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Step 3: Document Processing & Hashing
|
||
|
|
```
|
||
|
|
3a. NestJS Document Service:
|
||
|
|
- Receives files
|
||
|
|
- Validates file types and sizes
|
||
|
|
- Uploads to MinIO with unique IDs
|
||
|
|
- Generates SHA-256 hash of each document
|
||
|
|
- Creates document metadata records in PostgreSQL
|
||
|
|
|
||
|
|
3b. License Request:
|
||
|
|
- Created with status: DRAFT
|
||
|
|
- All documents linked via hashes
|
||
|
|
- No blockchain record yet
|
||
|
|
|
||
|
|
3c. API Response to Frontend:
|
||
|
|
- License request ID
|
||
|
|
- Document upload status
|
||
|
|
- License saved locally for editing
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Step 4: Blockchain Recording
|
||
|
|
```
|
||
|
|
4a. When citizen submits for approval:
|
||
|
|
- API aggregates all document hashes
|
||
|
|
- Creates combined SHA-256 (licenseHash)
|
||
|
|
- Calls smart contract via RPC
|
||
|
|
|
||
|
|
4b. Smart Contract Call:
|
||
|
|
POST https://besu-validator-1:8545
|
||
|
|
├─ Method: DocumentRegistrar.recordDocumentHash()
|
||
|
|
├─ Params:
|
||
|
|
│ ├─ licenseHash: bytes32
|
||
|
|
│ ├─ licenseType: "ResortLicense"
|
||
|
|
│ ├─ department: address (Tourism Dept)
|
||
|
|
│ └─ timestamp: uint256
|
||
|
|
└─ Result: Transaction receipt with block number
|
||
|
|
|
||
|
|
4c. QBFT Consensus:
|
||
|
|
- Transaction sent to all 4 validators
|
||
|
|
- Each validator verifies signature and state
|
||
|
|
- 3/4 validators must agree
|
||
|
|
- Block included in chain
|
||
|
|
- Event: DocumentHashRecorded emitted
|
||
|
|
|
||
|
|
4d. Database Update:
|
||
|
|
UPDATE license_requests
|
||
|
|
SET status = 'SUBMITTED',
|
||
|
|
blockchain_tx_hash = '0x...',
|
||
|
|
blockchain_block_num = 12345,
|
||
|
|
submitted_at = NOW()
|
||
|
|
WHERE request_id = 'LR-001'
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Step 5-6: Route to Departments (Parallel)
|
||
|
|
```
|
||
|
|
5a. Workflow Engine determines routing:
|
||
|
|
- License type: ResortLicense
|
||
|
|
- Query WorkflowRegistry for approval workflow
|
||
|
|
- Returns: [Tourism Department, Fire Safety Department]
|
||
|
|
- Mode: Parallel (can approve simultaneously)
|
||
|
|
|
||
|
|
5b. Create Approval Requests:
|
||
|
|
INSERT INTO approvals
|
||
|
|
├─ approval_id: 'APR-001-TOURISM'
|
||
|
|
├─ license_id: 'LR-001'
|
||
|
|
├─ department: 'Tourism'
|
||
|
|
├─ status: 'PENDING'
|
||
|
|
├─ assigned_to: [list of approver emails]
|
||
|
|
└─ created_at: NOW()
|
||
|
|
|
||
|
|
INSERT INTO approvals
|
||
|
|
├─ approval_id: 'APR-001-FIRE'
|
||
|
|
├─ license_id: 'LR-001'
|
||
|
|
├─ department: 'Fire Safety'
|
||
|
|
├─ status: 'PENDING'
|
||
|
|
├─ assigned_to: [list of approver emails]
|
||
|
|
└─ created_at: NOW()
|
||
|
|
|
||
|
|
5c. Webhook Notifications (via Redis Pub/Sub):
|
||
|
|
EventPublished: "approval.assigned"
|
||
|
|
├─ recipient: approver@tourism.gov.in
|
||
|
|
├─ action: "Resort License #LR-001 awaiting review"
|
||
|
|
└─ link: "https://gel-platform/approvals/APR-001-TOURISM"
|
||
|
|
|
||
|
|
6. Parallel Approval Assignment:
|
||
|
|
- Tourism Department reviews resort location & management
|
||
|
|
- Fire Safety Department reviews fire safety plan
|
||
|
|
- Both can review simultaneously
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Step 7-8: Department Approvals
|
||
|
|
```
|
||
|
|
7a. Tourism Approver Reviews:
|
||
|
|
Frontend shows:
|
||
|
|
├─ Applicant details (name, experience)
|
||
|
|
├─ Resort location (map, nearby facilities)
|
||
|
|
├─ Proposed capacity & amenities
|
||
|
|
├─ Property proof documents
|
||
|
|
└─ Can download or view embedded
|
||
|
|
|
||
|
|
7b. Tourism Approver Approves:
|
||
|
|
POST /approvals/APR-001-TOURISM/approve
|
||
|
|
├─ Body:
|
||
|
|
│ ├─ decision: "APPROVED"
|
||
|
|
│ ├─ comments: "Location suitable, management experienced"
|
||
|
|
│ └─ signature: signatureHash (if using digital signature)
|
||
|
|
└─ Auth: Department user credentials
|
||
|
|
|
||
|
|
7c. Backend Processing:
|
||
|
|
a) Update database:
|
||
|
|
UPDATE approvals
|
||
|
|
SET status = 'APPROVED',
|
||
|
|
reviewed_by = 'approver@tourism.gov.in',
|
||
|
|
reviewed_at = NOW(),
|
||
|
|
comments = 'Location suitable...'
|
||
|
|
WHERE approval_id = 'APR-001-TOURISM'
|
||
|
|
|
||
|
|
b) Record on blockchain:
|
||
|
|
Call ApprovalManager.recordApproval()
|
||
|
|
├─ licenseHash: 0x7f8c...a1b2
|
||
|
|
├─ department: 0xTourismDeptAddress
|
||
|
|
├─ status: APPROVED
|
||
|
|
├─ timestamp: block.timestamp
|
||
|
|
└─ Result: Event ApprovalRecorded emitted
|
||
|
|
|
||
|
|
c) Update workflow state (Redis cache):
|
||
|
|
KEY: "license:LR-001:approvals"
|
||
|
|
VALUE: {
|
||
|
|
"APR-001-TOURISM": {"status": "APPROVED", ...},
|
||
|
|
"APR-001-FIRE": {"status": "PENDING", ...}
|
||
|
|
}
|
||
|
|
|
||
|
|
7d. Fire Safety Approver Reviews & Approves (Parallel):
|
||
|
|
Similar process with fire safety specific documents
|
||
|
|
|
||
|
|
8. Parallel Completion:
|
||
|
|
Both departments complete their approvals
|
||
|
|
- Database updated
|
||
|
|
- Blockchain events recorded
|
||
|
|
- Workflow cache synchronized
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Step 9: Final Approval & NFT Minting
|
||
|
|
```
|
||
|
|
9a. Workflow Engine Monitors State:
|
||
|
|
Check all approvals for license LR-001
|
||
|
|
Result: 2/2 approvals = APPROVED
|
||
|
|
|
||
|
|
9b. Trigger License Approval:
|
||
|
|
a) Generate License Certificate:
|
||
|
|
- Template: ResortLicense_Template.pdf
|
||
|
|
- Fill with: Applicant name, Resort location, Date, etc.
|
||
|
|
- Upload to MinIO: /certificates/LR-001-cert.pdf
|
||
|
|
- Hash: SHA-256 of PDF
|
||
|
|
|
||
|
|
b) Prepare NFT Metadata:
|
||
|
|
{
|
||
|
|
"name": "Goa Resort License - [Resort Name]",
|
||
|
|
"description": "Blockchain-verified Resort License issued by...",
|
||
|
|
"image": "https://storage/license-badge.png",
|
||
|
|
"attributes": {
|
||
|
|
"license_type": "ResortLicense",
|
||
|
|
"issue_date": "2026-02-03",
|
||
|
|
"expiry_date": "2027-02-03",
|
||
|
|
"issuer": "Tourism Department, Goa",
|
||
|
|
"certificate_hash": "0xabcd...",
|
||
|
|
"license_request_hash": "0x7f8c...",
|
||
|
|
"applicant": "Resort Owner Name"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Upload to MinIO: /metadata/LR-001-metadata.json
|
||
|
|
|
||
|
|
c) Mint Soulbound NFT:
|
||
|
|
Call LicenseRequestNFT.mint()
|
||
|
|
├─ to: applicant_wallet_address
|
||
|
|
├─ licenseHash: 0x7f8c...a1b2
|
||
|
|
├─ metadataURI: "https://storage/metadata/LR-001-metadata.json"
|
||
|
|
├─ issuerDept: tourismDeptAddress
|
||
|
|
└─ Result: Transaction with tokenId
|
||
|
|
|
||
|
|
d) QBFT Consensus & Finalization:
|
||
|
|
- 3/4 validators approve mint transaction
|
||
|
|
- NFT created in smart contract state
|
||
|
|
- tokenId: 1001 (auto-incremented)
|
||
|
|
- ownerOf(1001) = applicant_wallet
|
||
|
|
- Event: Transfer(address(0), applicant, 1001)
|
||
|
|
|
||
|
|
e) Update Database:
|
||
|
|
UPDATE license_requests
|
||
|
|
SET status = 'APPROVED',
|
||
|
|
nft_token_id = 1001,
|
||
|
|
nft_address = '0xLicenseNFTContractAddress',
|
||
|
|
approved_at = NOW()
|
||
|
|
WHERE request_id = 'LR-001'
|
||
|
|
|
||
|
|
INSERT INTO audit_logs
|
||
|
|
VALUES (license_id='LR-001', action='APPROVED', ..., timestamp=NOW())
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Step 10: Notifications & State Update
|
||
|
|
```
|
||
|
|
10a. Send Approval Notification:
|
||
|
|
Webhook Event: "license.approved"
|
||
|
|
├─ recipient: citizen@email.com
|
||
|
|
├─ subject: "Your Resort License Has Been Approved!"
|
||
|
|
├─ body: "License #LR-001 approved on [date]"
|
||
|
|
└─ link: "https://gel-platform/licenses/LR-001"
|
||
|
|
|
||
|
|
10b. Update Frontend:
|
||
|
|
WebSocket notification to citizen's browser
|
||
|
|
├─ Status changed to: APPROVED
|
||
|
|
├─ Show NFT badge
|
||
|
|
├─ Enable download buttons
|
||
|
|
└─ Display approval timeline
|
||
|
|
|
||
|
|
10c. Cache Invalidation:
|
||
|
|
Redis invalidates:
|
||
|
|
├─ license:LR-001:* (all license data)
|
||
|
|
├─ citizen:citizen@email.com:licenses
|
||
|
|
└─ dashboard:pending-approvals
|
||
|
|
(Fresh data will be loaded on next request)
|
||
|
|
|
||
|
|
10d. Update Department Dashboards:
|
||
|
|
├─ Remove from "Pending Review" list
|
||
|
|
├─ Add to "Approved" list with approval details
|
||
|
|
└─ Show NFT minting confirmation
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Step 11: License Verification
|
||
|
|
```
|
||
|
|
11a. Citizen Downloads License Certificate:
|
||
|
|
GET /licenses/LR-001/certificate
|
||
|
|
|
||
|
|
11b. Certificate Generation:
|
||
|
|
a) Retrieve license metadata from DB
|
||
|
|
b) Get NFT details from blockchain
|
||
|
|
c) Generate PDF with all details + QR code
|
||
|
|
d) QR Code contains: https://gel-verify.goa.gov.in?verify=0x7f8c...a1b2
|
||
|
|
e) Return PDF
|
||
|
|
|
||
|
|
11c. Third-party Verification (e.g., Hotel Inspector):
|
||
|
|
a) Scan QR code on license certificate
|
||
|
|
b) GET https://gel-verify.goa.gov.in/verify?hash=0x7f8c...a1b2
|
||
|
|
|
||
|
|
c) Verification Service:
|
||
|
|
i. Query blockchain for this hash
|
||
|
|
ii. Check if NFT still valid (not revoked/burned)
|
||
|
|
iii. Return: {
|
||
|
|
"valid": true,
|
||
|
|
"license_type": "ResortLicense",
|
||
|
|
"holder": "Resort Name",
|
||
|
|
"issue_date": "2026-02-03",
|
||
|
|
"expiry_date": "2027-02-03",
|
||
|
|
"issuer": "Tourism Department"
|
||
|
|
}
|
||
|
|
iv. Inspector can verify instantly without needing central server
|
||
|
|
|
||
|
|
11d. On-Chain Verification:
|
||
|
|
Call LicenseRequestNFT.ownerOf(tokenId)
|
||
|
|
└─ Returns: citizen_address (verifying NFT still exists)
|
||
|
|
|
||
|
|
Call ApprovalManager.getApprovalChain(licenseHash)
|
||
|
|
└─ Returns: Complete approval history [Tourism: APPROVED, Fire: APPROVED]
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. Deployment Architecture
|
||
|
|
|
||
|
|
### Docker Compose Environment
|
||
|
|
|
||
|
|
All services run in isolated containers with defined networks and volumes.
|
||
|
|
|
||
|
|
#### Services Overview
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
version: '3.9'
|
||
|
|
|
||
|
|
services:
|
||
|
|
# Frontend
|
||
|
|
frontend:
|
||
|
|
image: node:18-alpine
|
||
|
|
build: ./frontend
|
||
|
|
container_name: gel-frontend
|
||
|
|
ports:
|
||
|
|
- "3000:3000"
|
||
|
|
environment:
|
||
|
|
- NEXT_PUBLIC_API_URL=http://api:3001
|
||
|
|
- NEXT_PUBLIC_BLOCKCHAIN_RPC=http://besu-1:8545
|
||
|
|
volumes:
|
||
|
|
- ./frontend:/app
|
||
|
|
- /app/node_modules
|
||
|
|
depends_on:
|
||
|
|
- api
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
|
||
|
|
# NestJS Backend API
|
||
|
|
api:
|
||
|
|
image: node:18-alpine
|
||
|
|
build: ./backend
|
||
|
|
container_name: gel-api
|
||
|
|
ports:
|
||
|
|
- "3001:3001"
|
||
|
|
environment:
|
||
|
|
- DATABASE_URL=postgresql://gel_user:${DB_PASSWORD}@postgres:5432/goa_gel
|
||
|
|
- REDIS_URL=redis://redis:6379
|
||
|
|
- MINIO_ENDPOINT=minio:9000
|
||
|
|
- BLOCKCHAIN_RPC=http://besu-1:8545
|
||
|
|
- BLOCKCHAIN_NETWORK_ID=1337
|
||
|
|
- API_SECRET_KEY=${API_SECRET_KEY}
|
||
|
|
volumes:
|
||
|
|
- ./backend:/app
|
||
|
|
- /app/node_modules
|
||
|
|
depends_on:
|
||
|
|
- postgres
|
||
|
|
- redis
|
||
|
|
- minio
|
||
|
|
- besu-1
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
healthcheck:
|
||
|
|
test: ["CMD", "curl", "-f", "http://localhost:3001/health"]
|
||
|
|
interval: 30s
|
||
|
|
timeout: 10s
|
||
|
|
retries: 3
|
||
|
|
|
||
|
|
# PostgreSQL Database
|
||
|
|
postgres:
|
||
|
|
image: postgres:15-alpine
|
||
|
|
container_name: gel-postgres
|
||
|
|
ports:
|
||
|
|
- "5432:5432"
|
||
|
|
environment:
|
||
|
|
- POSTGRES_DB=goa_gel
|
||
|
|
- POSTGRES_USER=gel_user
|
||
|
|
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||
|
|
volumes:
|
||
|
|
- postgres_data:/var/lib/postgresql/data
|
||
|
|
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
healthcheck:
|
||
|
|
test: ["CMD-SHELL", "pg_isready -U gel_user"]
|
||
|
|
interval: 10s
|
||
|
|
timeout: 5s
|
||
|
|
retries: 5
|
||
|
|
|
||
|
|
# Redis Cache
|
||
|
|
redis:
|
||
|
|
image: redis:7-alpine
|
||
|
|
container_name: gel-redis
|
||
|
|
ports:
|
||
|
|
- "6379:6379"
|
||
|
|
volumes:
|
||
|
|
- redis_data:/data
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
healthcheck:
|
||
|
|
test: ["CMD", "redis-cli", "ping"]
|
||
|
|
interval: 10s
|
||
|
|
timeout: 5s
|
||
|
|
retries: 5
|
||
|
|
|
||
|
|
# MinIO S3-compatible Storage
|
||
|
|
minio:
|
||
|
|
image: minio/minio:latest
|
||
|
|
container_name: gel-minio
|
||
|
|
ports:
|
||
|
|
- "9000:9000"
|
||
|
|
- "9001:9001"
|
||
|
|
environment:
|
||
|
|
- MINIO_ROOT_USER=minioadmin
|
||
|
|
- MINIO_ROOT_PASSWORD=${MINIO_PASSWORD}
|
||
|
|
volumes:
|
||
|
|
- minio_data:/minio_data
|
||
|
|
command: server /minio_data --console-address ":9001"
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
healthcheck:
|
||
|
|
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||
|
|
interval: 30s
|
||
|
|
timeout: 20s
|
||
|
|
retries: 3
|
||
|
|
|
||
|
|
# Hyperledger Besu Validator Nodes
|
||
|
|
besu-1:
|
||
|
|
image: hyperledger/besu:latest
|
||
|
|
container_name: gel-besu-1
|
||
|
|
ports:
|
||
|
|
- "8545:8545" # RPC
|
||
|
|
- "30303:30303" # P2P
|
||
|
|
volumes:
|
||
|
|
- ./besu/config.toml:/etc/besu/config.toml
|
||
|
|
- ./besu/genesis.json:/etc/besu/genesis.json
|
||
|
|
- ./besu/keys/node1:/opt/besu/keys
|
||
|
|
- besu_data_1:/data
|
||
|
|
environment:
|
||
|
|
- BESU_RPC_HTTP_ENABLED=true
|
||
|
|
- BESU_RPC_HTTP_HOST=0.0.0.0
|
||
|
|
- BESU_RPC_HTTP_PORT=8545
|
||
|
|
- BESU_RPC_WS_ENABLED=true
|
||
|
|
- BESU_RPC_WS_HOST=0.0.0.0
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
depends_on:
|
||
|
|
- besu-2
|
||
|
|
- besu-3
|
||
|
|
- besu-4
|
||
|
|
|
||
|
|
besu-2:
|
||
|
|
image: hyperledger/besu:latest
|
||
|
|
container_name: gel-besu-2
|
||
|
|
ports:
|
||
|
|
- "8546:8545"
|
||
|
|
- "30304:30303"
|
||
|
|
volumes:
|
||
|
|
- ./besu/config.toml:/etc/besu/config.toml
|
||
|
|
- ./besu/genesis.json:/etc/besu/genesis.json
|
||
|
|
- ./besu/keys/node2:/opt/besu/keys
|
||
|
|
- besu_data_2:/data
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
|
||
|
|
besu-3:
|
||
|
|
image: hyperledger/besu:latest
|
||
|
|
container_name: gel-besu-3
|
||
|
|
ports:
|
||
|
|
- "8547:8545"
|
||
|
|
- "30305:30303"
|
||
|
|
volumes:
|
||
|
|
- ./besu/config.toml:/etc/besu/config.toml
|
||
|
|
- ./besu/genesis.json:/etc/besu/genesis.json
|
||
|
|
- ./besu/keys/node3:/opt/besu/keys
|
||
|
|
- besu_data_3:/data
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
|
||
|
|
besu-4:
|
||
|
|
image: hyperledger/besu:latest
|
||
|
|
container_name: gel-besu-4
|
||
|
|
ports:
|
||
|
|
- "8548:8545"
|
||
|
|
- "30306:30303"
|
||
|
|
volumes:
|
||
|
|
- ./besu/config.toml:/etc/besu/config.toml
|
||
|
|
- ./besu/genesis.json:/etc/besu/genesis.json
|
||
|
|
- ./besu/keys/node4:/opt/besu/keys
|
||
|
|
- besu_data_4:/data
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
|
||
|
|
# Prometheus Monitoring
|
||
|
|
prometheus:
|
||
|
|
image: prom/prometheus:latest
|
||
|
|
container_name: gel-prometheus
|
||
|
|
ports:
|
||
|
|
- "9090:9090"
|
||
|
|
volumes:
|
||
|
|
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
|
||
|
|
- prometheus_data:/prometheus
|
||
|
|
command:
|
||
|
|
- '--config.file=/etc/prometheus/prometheus.yml'
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
|
||
|
|
# Grafana Dashboards
|
||
|
|
grafana:
|
||
|
|
image: grafana/grafana:latest
|
||
|
|
container_name: gel-grafana
|
||
|
|
ports:
|
||
|
|
- "3002:3000"
|
||
|
|
environment:
|
||
|
|
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
|
||
|
|
volumes:
|
||
|
|
- grafana_storage:/var/lib/grafana
|
||
|
|
- ./monitoring/grafana/provisioning:/etc/grafana/provisioning
|
||
|
|
depends_on:
|
||
|
|
- prometheus
|
||
|
|
networks:
|
||
|
|
- gel-network
|
||
|
|
|
||
|
|
networks:
|
||
|
|
gel-network:
|
||
|
|
driver: bridge
|
||
|
|
ipam:
|
||
|
|
config:
|
||
|
|
- subnet: 172.20.0.0/16
|
||
|
|
|
||
|
|
volumes:
|
||
|
|
postgres_data:
|
||
|
|
redis_data:
|
||
|
|
minio_data:
|
||
|
|
besu_data_1:
|
||
|
|
besu_data_2:
|
||
|
|
besu_data_3:
|
||
|
|
besu_data_4:
|
||
|
|
prometheus_data:
|
||
|
|
grafana_storage:
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Environment Configuration
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# .env file
|
||
|
|
DB_PASSWORD=your_secure_db_password
|
||
|
|
MINIO_PASSWORD=your_secure_minio_password
|
||
|
|
API_SECRET_KEY=your_secure_api_key
|
||
|
|
GRAFANA_PASSWORD=your_secure_grafana_password
|
||
|
|
|
||
|
|
# Optional: Domain configuration
|
||
|
|
FRONTEND_URL=https://gel-platform.goa.gov.in
|
||
|
|
API_URL=https://api.gel-platform.goa.gov.in
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Startup Process
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. Build all images
|
||
|
|
docker-compose build
|
||
|
|
|
||
|
|
# 2. Start all services
|
||
|
|
docker-compose up -d
|
||
|
|
|
||
|
|
# 3. Initialize database
|
||
|
|
docker-compose exec postgres psql -U gel_user -d goa_gel -f /docker-entrypoint-initdb.d/init.sql
|
||
|
|
|
||
|
|
# 4. Verify services
|
||
|
|
docker-compose ps
|
||
|
|
docker-compose logs -f api
|
||
|
|
|
||
|
|
# 5. Access services
|
||
|
|
# Frontend: http://localhost:3000
|
||
|
|
# API: http://localhost:3001
|
||
|
|
# MinIO Console: http://localhost:9001
|
||
|
|
# Prometheus: http://localhost:9090
|
||
|
|
# Grafana: http://localhost:3002
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 7. Key Technical Benefits
|
||
|
|
|
||
|
|
### Immutability & Trust
|
||
|
|
- Once a license is recorded on blockchain, it cannot be tampered with
|
||
|
|
- Full approval history is cryptographically verifiable
|
||
|
|
- Any party can independently verify license authenticity
|
||
|
|
|
||
|
|
### Transparency
|
||
|
|
- Multi-department approvals are publicly recorded
|
||
|
|
- Citizens can see real-time status of their requests
|
||
|
|
- Audit trail of every action is preserved
|
||
|
|
|
||
|
|
### Efficiency
|
||
|
|
- Parallel approval workflows reduce processing time
|
||
|
|
- Automated notifications keep stakeholders informed
|
||
|
|
- Real-time status updates via WebSocket/Redis
|
||
|
|
|
||
|
|
### Security
|
||
|
|
- API Key + Secret authentication (POC)
|
||
|
|
- JWT tokens for session management
|
||
|
|
- Role-based access control (RBAC)
|
||
|
|
- Immutable audit logs prevent tampering
|
||
|
|
|
||
|
|
### Scalability
|
||
|
|
- Off-chain document storage (MinIO)
|
||
|
|
- On-chain hashing ensures scalability
|
||
|
|
- Redis caching for high-traffic operations
|
||
|
|
- Horizontal scaling possible for all services
|
||
|
|
|
||
|
|
### Interoperability
|
||
|
|
- ERC-721 standard enables future integrations
|
||
|
|
- REST API for third-party systems
|
||
|
|
- Blockchain records can be shared with National Blockchain Federation
|
||
|
|
- Legacy system integration via adapters
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 8. Future Enhancements
|
||
|
|
|
||
|
|
### Phase 2 (Post-POC)
|
||
|
|
- OAuth 2.0 integration with DigiLocker (real, not mocked)
|
||
|
|
- Multi-signature smart contracts for critical decisions
|
||
|
|
- Insurance coverage integration
|
||
|
|
|
||
|
|
### Phase 3
|
||
|
|
- DAO governance for workflow changes
|
||
|
|
- Cross-chain interoperability (Cosmos/Polkadot)
|
||
|
|
- Mobile app for on-the-go approvals
|
||
|
|
|
||
|
|
### Phase 4
|
||
|
|
- AI-powered document verification
|
||
|
|
- National Blockchain Federation integration
|
||
|
|
- License marketplace for portability
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 9. File Locations
|
||
|
|
|
||
|
|
All diagrams and related files are located in:
|
||
|
|
```
|
||
|
|
/sessions/cool-elegant-faraday/mnt/Goa-GEL/
|
||
|
|
```
|
||
|
|
|
||
|
|
### Mermaid Diagram Files (.mermaid)
|
||
|
|
- `system-context.mermaid` - C4 Context diagram
|
||
|
|
- `container-architecture.mermaid` - Container architecture
|
||
|
|
- `blockchain-architecture.mermaid` - Blockchain layer details
|
||
|
|
- `workflow-state-machine.mermaid` - State transitions
|
||
|
|
- `data-flow.mermaid` - Sequence diagram
|
||
|
|
- `deployment-architecture.mermaid` - Docker Compose setup
|
||
|
|
|
||
|
|
### HTML Preview Files (.html)
|
||
|
|
- Each .mermaid file has a corresponding .html file for browser viewing
|
||
|
|
- Open in any modern web browser (Chrome, Firefox, Safari, Edge)
|
||
|
|
- Uses CDN-hosted mermaid.js for rendering
|
||
|
|
|
||
|
|
### Conversion to PNG
|
||
|
|
See the README.md file for multiple options to convert diagrams to PNG format.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 10. Getting Started
|
||
|
|
|
||
|
|
1. **Review Diagrams**
|
||
|
|
- Open .html files in browser for quick visualization
|
||
|
|
- Or visit mermaid.live to paste .mermaid content
|
||
|
|
|
||
|
|
2. **Understand Architecture**
|
||
|
|
- Start with system-context for high-level overview
|
||
|
|
- Move to container-architecture for technical details
|
||
|
|
- Deep-dive with blockchain-architecture for smart contracts
|
||
|
|
|
||
|
|
3. **Implement**
|
||
|
|
- Use deployment-architecture for Docker Compose setup
|
||
|
|
- Reference data-flow for integration points
|
||
|
|
- Review workflow-state-machine for business logic
|
||
|
|
|
||
|
|
4. **Documentation**
|
||
|
|
- Convert diagrams to PNG for presentations
|
||
|
|
- Include in technical documentation
|
||
|
|
- Share with stakeholders for feedback
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Document Version**: 1.0
|
||
|
|
**Platform**: Goa GEL (Goa Government E-License)
|
||
|
|
**Last Updated**: 2026-02-03
|
||
|
|
**Status**: POC Phase 1
|