mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-24 16:37:55 +00:00
feat(core): Add backend services, scripts, and initial test structure
This commit is contained in:
@@ -0,0 +1,350 @@
|
||||
# 🏛️ KYC Council Backend
|
||||
|
||||
Backend simulation of pallet-collective voting for KYC approvals.
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
**Purpose:** Decentralized KYC approval system without runtime changes
|
||||
|
||||
**Architecture:**
|
||||
- Backend tracks council votes (in-memory)
|
||||
- 60% threshold (e.g., 7/11 votes)
|
||||
- Auto-executes approve_kyc when threshold reached
|
||||
- Uses SUDO account to sign blockchain transactions
|
||||
|
||||
## 🔗 Chain Flow
|
||||
|
||||
```
|
||||
User applies → Blockchain (PENDING) → Council votes → Backend auto-approves → Welati NFT minted
|
||||
```
|
||||
|
||||
**Why SUDO account?**
|
||||
- `identityKyc.approveKyc()` requires `EnsureRoot` origin
|
||||
- Backend signs transactions on behalf of council
|
||||
- Alternative: Change runtime to accept council origin (not needed for MVP)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Installation
|
||||
|
||||
### 1. Install Dependencies
|
||||
|
||||
```bash
|
||||
cd /home/mamostehp/pwap/backend
|
||||
npm install
|
||||
```
|
||||
|
||||
### 2. Configure Environment
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
nano .env
|
||||
```
|
||||
|
||||
**Required variables:**
|
||||
```env
|
||||
WS_ENDPOINT=wss://ws.pezkuwichain.io
|
||||
SUDO_SEED=your_sudo_seed_phrase_here
|
||||
PORT=3001
|
||||
```
|
||||
|
||||
⚠️ **Security Warning:** Keep SUDO_SEED secret! Use a dedicated account for KYC approvals only.
|
||||
|
||||
### 3. Start Server
|
||||
|
||||
**Development (with hot reload):**
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
**Production:**
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📡 API Endpoints
|
||||
|
||||
### Council Management
|
||||
|
||||
#### Add Council Member
|
||||
```bash
|
||||
POST /api/council/add-member
|
||||
{
|
||||
"address": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
|
||||
"signature": "0x..." // TODO: Implement signature verification
|
||||
}
|
||||
```
|
||||
|
||||
#### Remove Council Member
|
||||
```bash
|
||||
POST /api/council/remove-member
|
||||
{
|
||||
"address": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Council Members
|
||||
```bash
|
||||
GET /api/council/members
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"members": ["5DFw...Dwd3", "5Grw...utQY"],
|
||||
"totalMembers": 2,
|
||||
"threshold": 0.6,
|
||||
"votesRequired": 2
|
||||
}
|
||||
```
|
||||
|
||||
#### Sync with Noter Tiki Holders
|
||||
```bash
|
||||
POST /api/council/sync-notaries
|
||||
```
|
||||
|
||||
Auto-fetches first 10 Noter tiki holders from blockchain and updates council.
|
||||
|
||||
---
|
||||
|
||||
### KYC Voting
|
||||
|
||||
#### Propose KYC Approval
|
||||
```bash
|
||||
POST /api/kyc/propose
|
||||
{
|
||||
"userAddress": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
|
||||
"proposerAddress": "5DFwqK698vL4gXHEcanaewnAqhxJ2rjhAogpSTHw3iwGDwd3",
|
||||
"signature": "0x..."
|
||||
}
|
||||
```
|
||||
|
||||
**Logic:**
|
||||
- Proposer auto-votes AYE
|
||||
- If threshold already met (e.g., 1/1 member), auto-executes immediately
|
||||
|
||||
#### Vote on Proposal
|
||||
```bash
|
||||
POST /api/kyc/vote
|
||||
{
|
||||
"userAddress": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
|
||||
"voterAddress": "5DFwqK698vL4gXHEcanaewnAqhxJ2rjhAogpSTHw3iwGDwd3",
|
||||
"approve": true,
|
||||
"signature": "0x..."
|
||||
}
|
||||
```
|
||||
|
||||
**Approve:** true = AYE, false = NAY
|
||||
|
||||
**Auto-execute:** If votes reach threshold, backend signs and submits `approve_kyc` transaction.
|
||||
|
||||
#### Get Pending Proposals
|
||||
```bash
|
||||
GET /api/kyc/pending
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"pending": [
|
||||
{
|
||||
"userAddress": "5Grw...utQY",
|
||||
"proposer": "5DFw...Dwd3",
|
||||
"ayes": ["5DFw...Dwd3", "5HpG...vSKr"],
|
||||
"nays": [],
|
||||
"timestamp": 1700000000000,
|
||||
"votesCount": 2,
|
||||
"threshold": 7,
|
||||
"status": "VOTING"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Council Membership Rules
|
||||
|
||||
### Initial Setup
|
||||
- **1 member:** Founder delegate (hardcoded: `5DFwqK698vL4gXHEcanaewnAqhxJ2rjhAogpSTHw3iwGDwd3`)
|
||||
- **Threshold:** 1/1 = 100% (single vote approves)
|
||||
|
||||
### Growth Path
|
||||
1. **Add Noter holders:** Use `/api/council/sync-notaries` to fetch first 10 Noter tiki holders
|
||||
2. **Council size:** 11 members (1 founder + 10 notaries)
|
||||
3. **Threshold:** 7/11 = 63.6% (60% threshold met)
|
||||
|
||||
### Automatic Updates
|
||||
- When Noter loses tiki → Remove from council
|
||||
- When new Noter available → Add to council (first 10 priority)
|
||||
- If no Notaries available → Serok (president) can appoint manually
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Test 1: Single Member (Founder Only)
|
||||
```bash
|
||||
# 1. Start backend
|
||||
npm run dev
|
||||
|
||||
# 2. Get council members
|
||||
curl http://localhost:3001/api/council/members
|
||||
|
||||
# Expected: 1 member (founder delegate)
|
||||
|
||||
# 3. User applies KYC (via frontend)
|
||||
# 4. Propose approval
|
||||
curl -X POST http://localhost:3001/api/kyc/propose \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"userAddress": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
|
||||
"proposerAddress": "5DFwqK698vL4gXHEcanaewnAqhxJ2rjhAogpSTHw3iwGDwd3"
|
||||
}'
|
||||
|
||||
# Expected: Auto-execute (1/1 threshold reached)
|
||||
```
|
||||
|
||||
### Test 2: 3 Members
|
||||
```bash
|
||||
# 1. Add 2 notaries
|
||||
curl -X POST http://localhost:3001/api/council/add-member \
|
||||
-d '{"address": "5HpG...vSKr"}'
|
||||
|
||||
curl -X POST http://localhost:3001/api/council/add-member \
|
||||
-d '{"address": "5FLe...dXRp"}'
|
||||
|
||||
# 2. Council: 3 members, threshold = 2 votes (60% of 3 = 1.8 → ceil = 2)
|
||||
|
||||
# 3. Propose
|
||||
curl -X POST http://localhost:3001/api/kyc/propose \
|
||||
-d '{
|
||||
"userAddress": "5Grw...utQY",
|
||||
"proposerAddress": "5DFw...Dwd3"
|
||||
}'
|
||||
|
||||
# Status: 1/2 (proposer voted AYE)
|
||||
|
||||
# 4. Vote from member 2
|
||||
curl -X POST http://localhost:3001/api/kyc/vote \
|
||||
-d '{
|
||||
"userAddress": "5Grw...utQY",
|
||||
"voterAddress": "5HpG...vSKr",
|
||||
"approve": true
|
||||
}'
|
||||
|
||||
# Expected: Auto-execute (2/2 threshold reached) ✅
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### Health Check
|
||||
```bash
|
||||
GET /health
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"blockchain": "connected",
|
||||
"sudoAccount": "5DFw...Dwd3",
|
||||
"councilMembers": 11,
|
||||
"pendingVotes": 3
|
||||
}
|
||||
```
|
||||
|
||||
### Console Logs
|
||||
```
|
||||
🔗 Connecting to PezkuwiChain...
|
||||
✅ Sudo account loaded: 5DFw...Dwd3
|
||||
✅ Connected to blockchain
|
||||
📊 Chain: PezkuwiChain
|
||||
🏛️ Runtime version: 106
|
||||
|
||||
🚀 KYC Council Backend running on port 3001
|
||||
📊 Council members: 1
|
||||
🎯 Threshold: 60%
|
||||
|
||||
📝 KYC proposal created for 5Grw...utQY by 5DFw...Dwd3
|
||||
📊 Votes: 1/1 (1 members, 60% threshold)
|
||||
🎉 Threshold reached for 5Grw...utQY! Executing approve_kyc...
|
||||
📡 Transaction status: Ready
|
||||
📡 Transaction status: InBlock
|
||||
✅ KYC APPROVED for 5Grw...utQY
|
||||
🏛️ User will receive Welati NFT automatically
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Integration with Frontend
|
||||
|
||||
### Option A: Direct Backend API Calls
|
||||
Frontend calls backend endpoints directly (simpler for MVP).
|
||||
|
||||
```typescript
|
||||
// Propose KYC approval
|
||||
const response = await fetch('http://localhost:3001/api/kyc/propose', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
userAddress: application.address,
|
||||
proposerAddress: selectedAccount.address,
|
||||
signature: await signMessage(...)
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
### Option B: Blockchain Events + Backend Sync
|
||||
Backend listens to blockchain events and auto-tracks proposals (future enhancement).
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Security Considerations
|
||||
|
||||
1. **SUDO Account Protection:**
|
||||
- Use dedicated hardware wallet (Ledger recommended)
|
||||
- Only use for KYC approvals, nothing else
|
||||
- Consider multi-sig in production
|
||||
|
||||
2. **Signature Verification:**
|
||||
- TODO: Implement Polkadot signature verification
|
||||
- Prevent vote spam from non-members
|
||||
|
||||
3. **Rate Limiting:**
|
||||
- Add rate limiting to API endpoints
|
||||
- Prevent DoS attacks
|
||||
|
||||
4. **Audit Trail:**
|
||||
- Log all votes to database (future enhancement)
|
||||
- Track council member changes
|
||||
|
||||
---
|
||||
|
||||
## 📝 TODO
|
||||
|
||||
- [ ] Implement signature verification
|
||||
- [ ] Add database persistence (replace in-memory Maps)
|
||||
- [ ] Add rate limiting middleware
|
||||
- [ ] Add automated council sync cron job
|
||||
- [ ] Add multi-sig support for sudo account
|
||||
- [ ] Add audit logging
|
||||
- [ ] Add Prometheus metrics
|
||||
- [ ] Add Docker support
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
**Backend Developer:** [Your contact]
|
||||
**Runtime Issues:** Check `/Pezkuwi-SDK/pezkuwi/pallets/identity-kyc`
|
||||
**Frontend Integration:** See `/pwap/ADMIN_KYC_GUIDE.md`
|
||||
|
||||
---
|
||||
|
||||
**Version:** 1.0 (Backend Council MVP)
|
||||
**Last Updated:** 17 Kasım 2025
|
||||
Reference in New Issue
Block a user