# 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