Version: 1.0
Last Updated: October 30, 2025
Platform: Web3-Enabled Comic Publishing and NFT Marketplace
- Executive Summary
- System Architecture
- Technology Stack
- User Roles and Authentication
- Core Features
- Database Architecture
- Smart Contract Integration
- API Documentation
- Frontend Architecture
- NFT and Blockchain Features
- IPFS Integration
- Monetization System
- Security and Access Control
- Deployment Guide
- Development Workflow
- Troubleshooting
- Future Roadmap
- Pitch Deck Doc [https://drive.google.com/file/d/1IkCd9hBZkaqNjHMH1npsIUC9pV2Gl038/view?usp=drivesdk]
19 HashGraph Certification [https://drive.google.com/file/d/17Q6ycA-Jx9drDcipKROGoyr7tM5kcGIA/view?usp=drivesdk]
Quiva is a next-generation comic platform that bridges traditional comic publishing with Web3 technology. It enables creators and fans to engage through decentralized publishing, NFT minting, games, and immersive stories. The platform integrates blockchain technology to allow creators to mint, own, and monetize their comics securely while providing readers with both free and premium content.
- Blockchain Integration: Comics can be minted as NFTs with built-in royalties
- Dual Publishing Model: Support for (free/paid) which are NFT-based publishing
- IPFS Storage: Decentralized storage ensuring permanent availability
- Smart Contract Marketplace: On-chain trading with automated royalties
- Creator-First Approach: Tools designed for comic creators' needs
- Hedera Network: Leveraging Hedera Smart Contract Service,Hedera Token Service for fast, low-cost transactions
For Creators:
- Own The copies of content through NFTs.
- Multiple monetization options (free, pay-per-read, NFT sales)
- Automated royalty payments
- Direct connection with fans
- Decentralized content hosting
For Readers:
- Access to diverse comic library
- Option to own the NFT version of the comics
- Support favorite creators directly
- No platform lock-in (IPFS-based content)
┌─────────────────────────────────────────────────────────────┐
│ Client Layer (Frontend) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Next.js │ │ React/TSX │ │ TailwindCSS │ │
│ │ App Router │ │ Components │ │ Styling │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Wallet Integration Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Hashpack
RainbowKit
│ Wagmi │ │ │ │ Viem
│ │ Wallet UI │ │ Web3 Hooks │ │ Ethereum │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Backend API Layer (Node.js) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Express.js │ │ TypeScript │ │ REST API │ │
│ │ Routing │ │ Services │ │ Endpoints │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌───────────┴───────────┐
▼ ▼
┌─────────────────────────┐ ┌─────────────────────────┐
│ Database Layer │ │ Blockchain Layer │
│ ┌──────────────────┐ │ │ ┌──────────────────┐ │
│ │ MongoDB │ │ │ │ Smart Contract │ │
│ │ User Data │ │ │ │ (Hedera EVM) │ │
│ │ Comics Metadata │ │ │ │ ERC-1155 NFTs │ │
│ │ Transactions │ │ │ └──────────────────┘ │
│ └──────────────────┘ │ │ ┌──────────────────┐ │
│ │ │ │ IPFS Storage │ │
│ │ │ │ Comic Pages │ │
│ │ │ │ Metadata JSON │ │
│ │ │ └──────────────────┘ │
└─────────────────────────┘ └─────────────────────────┘
Controllers Layer (src/controllers/)
- Handle HTTP requests and responses
- Request validation and sanitization
- Error handling and status codes
Services Layer (src/services/ and src/features/)
- Business logic implementation
- Data transformation
- External service integration
Repository Layer (src/models/)
- Data access abstraction
- MongoDB schema definitions
- Database query operations
Middleware Layer (src/middleware/)
- Authentication verification
- Rate limiting
- Role-based access control
- Request logging
- Frontend Application (Next.js 14+ with App Router)
- Backend API (Express.js + TypeScript)
- Smart Contracts (Solidity on Hedera EVM)
- IPFS Network (Pinata Gateway)
- Database (MongoDB Atlas)
- Wallet Integration (Hashpack,RainbowKit + Wagmi)
- Blockchain Network (Hedera Testnet)
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 15.x | React framework with App Router |
| React | 18.x | UI component library |
| TypeScript | 5.x | Type-safe JavaScript |
| TailwindCSS | 3.x | Utility-first CSS framework |
| RainbowKit | 2.x | Wallet connection UI |
| Wagmi | 2.x | React hooks for Ethereum |
| Viem | 2.x | TypeScript Ethereum library |
| Redux Toolkit | 2.x | State management |
| React Query | 5.x | Server state management |
| Lucide React | Latest | Icon library |
| Technology | Version | Purpose |
|---|---|---|
| Node.js | 18+ | JavaScript runtime |
| Express.js | 4.x | Web application framework |
| TypeScript | 5.x | Type-safe development |
| MongoDB | 6.x | NoSQL database |
| Mongoose | 8.x | MongoDB object modeling |
| Ethers.js | 6.x | Ethereum library for backend |
| JWT | 9.x | Authentication tokens |
| Bcrypt | 5.x | Password hashing |
| Nodemailer | 6.x | Email service |
| Multer | 1.x | File upload handling |
| Technology | Network | Purpose |
|---|---|---|
| Hedera Testnet | ID: 296 | Primary blockchain network |
| Solidity | 0.8.20 | Smart contract language |
| ERC-1155 | Standard | Multi-token NFT standard |
| IPFS | Decentralized | Content storage |
| Pinata | Gateway | IPFS pinning service |
- Package Manager: npm/yarn
- Version Control: Git
- API Testing: Postman/Thunder Client
- Linting: ESLint + Prettier
- Testing: Jest (planned)
- CI/CD: GitHub Actions (planned)
export enum Roles {
READER = "reader",
CREATOR = "creator",
ADMIN = "admin",
SUPERADMIN = "superadmin"
}READER
- Browse and read free comics
- Purchase paid comics
- Buy NFT comics from marketplace
- Manage reading library
- Follow creators
CREATOR
- All READER permissions
- Upload and publish comics
- Create NFT collections
- Set pricing and royalties
- View earnings analytics
- Manage comic library
- List NFTs on marketplace
ADMIN
- All CREATOR permissions
- Approve creator accounts
- Moderate content
- View platform analytics
- Manage featured content
SUPERADMIN
- All ADMIN permissions
- System configuration
- User management
- Platform settings
- Database access
// Flow:
1. User enters email
2. System generates 6-digit OTP
3. OTP sent via Nodemailer
4. User verifies OTP
5. JWT token issuedEndpoints:
POST /api/auth/send-otp- Request OTPPOST /api/auth/verify-otp- Verify OTP and login
OTP Specifications:
- Length: 6 digits
- Validity: 10 minutes
- Rate Limit: 1 request per minute per email
- Storage: MongoDB with expiry
// Flow:
1. User connects wallet (RainbowKit)
2. System generates nonce message
3. User signs message with wallet
4. Backend verifies signature
5. JWT token issuedSupported Wallets:
- MetaMask
- WalletConnect
- Coinbase Wallet
- Rainbow Wallet
- And all RainbowKit supported wallets
Endpoints:
POST /api/auth/wallet/message- Get sign messagePOST /api/auth/wallet/verify- Verify signature and login
interface IUser {
email?: string;
emailVerified: boolean;
walletAddress?: string;
username?: string;
displayName?: string;
bio?: string;
nonce?: string; // For wallet authentication
avatar?: string;
banner?: string;
role: Roles[]; // Array to support multiple roles
creatorProfile?: {
penName?: string;
genres?: string[];
verified: boolean;
};
onboardingCompleted: boolean;
createdAt: Date;
lastLogin: Date;
}{
userId: string; // MongoDB ObjectId
email?: string;
walletAddress?: string;
role: string[];
iat: number; // Issued at
exp: number; // Expires at (7 days default)
}// Required fields during onboarding:
interface OnboardingRequest {
username: string; // Unique, 3-30 characters
displayName?: string;
bio?: string;
role: "reader" | "creator";
// Additional for creators:
penName?: string;
genres?: string[];
}Steps:
- User authenticates (email or wallet)
- Check if
onboardingCompleted === false - Show onboarding form
- User selects role and provides info
- System validates username uniqueness
- Profile created
- Set
onboardingCompleted = true
Method 1: Script-Based Creation
- AI-assisted comic generation (future feature)
- Script-to-comic conversion
- Automated panel layout
Method 2: Manual Upload
- Upload individual pages
- Drag-and-drop interface
- Support formats: PNG, JPG, WEBP
- Max file size: 10MB per page
- Recommended: 1200x1800px resolution
Step 1: Comic Details
├── Title (required, max 200 chars)
├── Description (required, max 1000 chars)
├── Cover Image (optional)
├── Genres (multi-select, required)
├── Tags (optional)
└── Age Rating (everyone/teen/mature)
Step 2: Upload Pages
├── Upload method selection
├── Page upload (minimum 1 page)
├── Page reordering
└── Preview pages
Step 3: Monetization
├── Publishing Type:
│ ├── Free (accessible to all)
│ └── Pay-Per-Read (set price in HBAR)
├── NFT Minting (optional):
│ ├── Enable/Disable
│ ├── NFT Copies (max supply)
│ ├── Mint Price (in HBAR)
│ └── Royalty % (default 10%)
└── Confirmation
Step 4: IPFS Upload (if NFT enabled)
├── Upload cover image to IPFS
├── Upload all pages to IPFS
├── Generate metadata JSON
├── Upload metadata to IPFS
└── Get IPFS CIDs
Step 5: Blockchain Minting (if NFT enabled)
├── Check creator approval status
├── Approve creator (if needed)
├── Mint NFT on smart contract
├── Receive tokenId
└── Store blockchain data
Step 6: Database Storage
├── Create comic record
├── Store IPFS hashes
├── Store tokenId and contract address
├── Set publishing status
└── Mark as published
- Instant access
- No wallet required
- Page-by-page navigation
- Responsive reader interface
- Wallet connection required
- One-time payment for lifetime access
- Payment in HBAR
- Access tracked on blockchain
- Offline reading (future)
- Purchase from marketplace
- Own as collectible
- Transfer/resell capability
- Proof of ownership on-chain
- Creator royalties on resales
// Creator can list minted NFTs
interface ListingParams {
tokenId: bigint;
pricePerToken: bigint; // in wei (HBAR)
amount: bigint; // quantity to list
}
// Smart contract function
function listComic(
uint256 tokenId,
uint256 pricePerToken,
uint256 amount
) external;Listing Process:
- Creator mints NFT
- Creator calls
listComic()function - NFT becomes available on marketplace
- Buyers can purchase listed amounts
- Creator receives payment minus platform fee
// Anyone can purchase listed NFTs
interface PurchaseParams {
tokenId: bigint;
seller: address;
amount: bigint;
}
// Smart contract function
function purchaseComic(
uint256 tokenId,
address seller,
uint256 amount
) external payable;Purchase Process:
- Buyer connects wallet
- Selects NFT from marketplace
- Specifies quantity to purchase
- Approves transaction
- Smart contract transfers NFT
- Payment split: (creator - platform fee)
- Access granted to comic content
- By Genre: Action, Adventure, Fantasy, Sci-Fi, etc.
- By Price: Free, Paid, NFT
- By Creator: Follow favorite creators
- By Rating: User ratings
- By Release Date: Newest first
- By Popularity: Most viewed/liked
- View all published comics
- Draft management
- Edit comic details
- View statistics per comic
- Mint NFTs for existing comics
interface EarningsData {
totalEarnings: number; // Total HBAR earned
readers: number; // Unique readers count
recentIncome: number; // Last 30 days
topComics: Array<{
title: string;
earnings: number;
readers: number;
}>;
transactionHistory: Transaction[];
}Metrics Displayed:
- Total lifetime earnings
- Monthly earnings trend
- Top performing comics
- Reader demographics
- Transaction history
- Pending withdrawals
// Withdraw earnings from smart contract
function withdrawEarnings() external;
// Platform tracks:
- Available balance
- Minimum withdrawal: 10 HBAR
- Transaction history
- Gas fee estimatesPlanned features:
- Story-based games tied to comic universes
- Interactive fiction
- Mini-games related to characters
- Reward system for gameplay
- NFT rewards for achievements
{
_id: ObjectId,
email: String (optional, unique, sparse),
emailVerified: Boolean,
walletAddress: String (optional, unique, sparse),
username: String (unique, 3-30 chars),
displayName: String (max 50 chars),
bio: String (max 500 chars),
nonce: String (for wallet auth),
avatar: String (URL),
banner: String (URL),
role: [String], // ["reader", "creator"]
creatorProfile: {
penName: String,
genres: [String],
verified: Boolean
},
onboardingCompleted: Boolean,
createdAt: Date,
lastLogin: Date
}Indexes:
email(unique, sparse)walletAddress(unique, sparse)username(unique)
{
_id: ObjectId,
creatorId: ObjectId (ref: Users),
title: String (required, max 200),
description: String (required, max 1000),
coverImage: String (IPFS URI or URL),
genre: [String] (required),
tags: [String],
creationType: String ("script" | "upload"),
chapters: [ObjectId] (ref: Chapters),
totalPages: Number,
status: String ("draft" | "published"),
publishType: String ("free" | "nft"),
price: Number (in HBAR, for pay-per-read),
nftDetails: {
mintStatus: String ("pending" | "minted" | "failed"),
tokenId: String,
contractAddress: String,
maxSupply: Number,
currentSupply: Number,
royaltyPercentage: Number,
metadataURI: String (IPFS URI),
coverImageIPFS: String (IPFS CID),
pagesIPFS: [String] (array of IPFS CIDs)
},
views: Number,
likes: Number,
createdAt: Date,
updatedAt: Date,
publishedAt: Date
}Indexes:
creatorIdstatuspublishTypegenrecreatedAt(descending)publishedAt(descending)nftDetails.tokenId
{
_id: ObjectId,
comicId: ObjectId (ref: Comics),
chapterNumber: Number,
title: String,
pages: [{
pageNumber: Number,
imageUrl: String, // Regular URL or IPFS
ipfsHash: String // If uploaded to IPFS
}],
publishedAt: Date,
createdAt: Date
}Indexes:
comicIdchapterNumber
{
_id: ObjectId,
userId: ObjectId (ref: Users),
comicId: ObjectId (ref: Comics),
type: String ("purchase" | "mint" | "list" | "withdraw"),
// Blockchain details
txHash: String (transaction hash),
from: String (wallet address),
to: String (wallet address),
tokenId: String,
// Financial details
amount: Number (in HBAR),
currency: String ("HBAR"),
platformFee: Number,
creatorEarnings: Number,
status: String ("pending" | "completed" | "failed"),
createdAt: Date,
completedAt: Date
}Indexes:
userIdcomicIdtxHash(unique)typestatuscreatedAt(descending)
{
_id: ObjectId,
email: String,
code: String (6 digits),
createdAt: Date, // Auto-expires after 10 minutes
expiresAt: Date
}TTL Index:
createdAtwith expiration: 600 seconds (10 minutes)
Contract Name: QuivaComics
Standard: ERC-1155 (Multi-Token Standard)
Network: Hedera Testnet (Chain ID: 296)
Contract Address: 0xF5CBD0241D176C6cF35564d2F5b701F74a0756E8
RPC URL: https://testnet.hashio.io/api
Block Explorer: https://hashscan.io/testnet/
// Approve a creator to mint comics
function approveCreator(address creator) external onlyOwner;
// Check if address is approved creator
mapping(address => bool) public approvedCreators;Usage:
- Only contract owner can approve creators
- Required before a creator can mint NFTs
- One-time approval per creator address
function mintComic(
string memory comicId,
string memory metadataURI,
uint256 maxSupply,
uint256 royaltyBasisPoints
) external returns (uint256 tokenId);Parameters:
comicId: Unique identifier for the comicmetadataURI: IPFS URI containing NFT metadatamaxSupply: Maximum number of NFTs that can existroyaltyBasisPoints: Royalty percentage (1000 = 10%)
Returns:
tokenId: Unique token ID for the minted comic
Events Emitted:
event ComicMinted(
uint256 indexed tokenId,
address indexed creator,
string comicId,
uint256 maxSupply
);function listComic(
uint256 tokenId,
uint256 pricePerToken,
uint256 amount
) external;Parameters:
tokenId: The NFT token ID to listpricePerToken: Price in wei (HBAR) per NFTamount: Quantity to list for sale
Requirements:
- Caller must own the NFTs
- Caller must have sufficient balance
- Listing must not exceed owned amount
Events Emitted:
event ComicListed(
uint256 indexed tokenId,
address indexed seller,
uint256 pricePerToken,
uint256 amount
);function purchaseComic(
uint256 tokenId,
address seller,
uint256 amount
) external payable;Parameters:
tokenId: The NFT to purchaseseller: Address of the selleramount: Quantity to purchase
Payment:
- Must send exact amount:
pricePerToken * amount - Platform fee deducted (default: 2.5%)
- Remainder goes to seller
- Royalties paid to original creator on secondary sales
Events Emitted:
event ComicPurchased(
uint256 indexed tokenId,
address indexed buyer,
address indexed seller,
uint256 amount
);function cancelListing(uint256 tokenId) external;Requirements:
- Caller must be the seller
- Listing must be active
Events Emitted:
event ComicListingCancelled(
uint256 indexed tokenId,
address indexed seller
);function updateListing(
uint256 tokenId,
uint256 newPrice,
uint256 newAmount
) external;Requirements:
- Caller must be the seller
- New amount must not exceed owned balance
function withdrawEarnings() external;Functionality:
- Transfers accumulated earnings to caller
- Tracks earnings per user automatically
- Emits Withdrawal event
uint256 public constant MAX_ROYALTY = 3000; // 30%
uint256 public constant MAX_PLATFORM_FEE = 1000; // 10%
uint256 public PLATFORM_FEE = 250; // 2.5% default// Get comic details
function getComic(uint256 tokenId)
external view returns (
uint256 tokenId,
address creator,
string memory metadataURI,
uint256 maxSupply,
uint256 currentSupply,
uint256 royaltyPercentage,
bool isActive
);
// Get listing details
function getListing(uint256 tokenId, address seller)
external view returns (
address seller,
uint256 pricePerToken,
uint256 amount,
bool isActive
);
// Check user's NFT balance
function balanceOf(address account, uint256 tokenId)
external view returns (uint256);
// Get user's earnings
mapping(address => uint256) public earnings;import { useWriteContract } from 'wagmi';
import { QUIVA_COMICS_ABI, QUIVA_COMICS_ADDRESS } from '@/contracts';
const { writeContract } = useWriteContract();
const mintNFT = async () => {
await writeContract({
address: QUIVA_COMICS_ADDRESS,
abi: QUIVA_COMICS_ABI,
functionName: 'mintComic',
args: [
comicId, // e.g., "comic_1234567_userId"
metadataURI, // e.g., "ipfs://QmXXX..."
BigInt(maxSupply), // e.g., BigInt(100)
BigInt(1000) // 10% royalty
],
account: address,
chain: hederaTestnet
});
};import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider(
'https://testnet.hashio.io/api'
);
const ownerWallet = new ethers.Wallet(PRIVATE_KEY, provider);
const contract = new ethers.Contract(
QUIVA_COMICS_ADDRESS,
QUIVA_COMICS_ABI,
ownerWallet
);
const approveCreator = async (creatorAddress: string) => {
const tx = await contract.approveCreator(creatorAddress);
await tx.wait();
console.log('Creator approved:', tx.hash);
};Development: http://localhost:5000/api
Production: https://api.quiva.io/api
POST /auth/send-otp
Content-Type: application/json
{
"email": "user@example.com"
}
Response 200:
{
"success": true,
"message": "OTP sent to email"
}POST /auth/verify-otp
Content-Type: application/json
{
"email": "user@example.com",
"code": "123456"
}
Response 200:
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": "507f1f77bcf86cd799439011",
"email": "user@example.com",
"role": ["reader"],
"username": "johndoe"
},
"isNewUser": false
}POST /auth/wallet/message
Content-Type: application/json
{
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}
Response 200:
{
"message": "Sign this message to authenticate: <nonce>"
}POST /auth/wallet/verify
Content-Type: application/json
{
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"message": "Sign this message...",
"signature": "0x..."
}
Response 200:
{
"success": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": { ... },
"isNewUser": true
}POST /users/onboarding
Authorization: Bearer <token>
Content-Type: application/json
{
"username": "johndoe",
"displayName": "John Doe",
"bio": "Comic enthusiast",
"role": "creator",
"penName": "JD Comics",
"genres": ["action", "sci-fi"]
}
Response 200:
{
"success": true,
"user": { ... }
}GET /users/:id
Authorization: Bearer <token>
Response 200:
{
"success": true,
"user": {
"id": "507f1f77bcf86cd799439011",
"username": "johndoe",
"displayName": "John Doe",
"bio": "Comic enthusiast",
"avatar": "https://...",
"role": ["creator"],
"creatorProfile": {
"penName": "JD Comics",
"genres": ["action", "sci-fi"],
"verified": false
}
}
}PUT /users/:id/profile
Authorization: Bearer <token>
Content-Type: multipart/form-data
Form Fields:
- displayName: string
- bio: string
- avatar: file (optional)
- banner: file (optional)
- penName: string (creators only)
- genres: string[] (creators only)
Response 200:
{
"success": true,
"message": "Profile updated",
"user": { ... }
}POST /users/become-creator
Authorization: Bearer <token>
Content-Type: application/json
{
"penName": "JD Comics",
"genres": ["action", "sci-fi"]
}
Response 200:
{
"success": true,
"message": "You are now a creator!"
}POST /comics
Authorization: Bearer <token>
Content-Type: application/json
{
"title": "My First Comic",
"description": "An epic adventure...",
"genre": ["action", "adventure"],
"tags": ["superhero", "manga"],
"ageRating": "teen",
"creationType": "upload"
}
Response 201:
{
"success": true,
"comic": {
"_id": "507f...",
"title": "My First Comic",
"status": "draft",
...
}
}POST /comics/:comicId/pages
Authorization: Bearer <token>
Content-Type: multipart/form-data
Form Fields:
- pages: file[] (multiple files)
- chapterNumber: number
Response 200:
{
"success": true,
"message": "Pages uploaded",
"uploadedPages": 15
}POST /comics/:comicId/publish
Authorization: Bearer <token>
Content-Type: application/json
{
"publishType": "free" | "nft",
"price": 5.00, // For pay-per-read
"mintAsNFT": true,
"nftCopies": 100,
"nftPrice": 10.00,
"royaltyPercentage": 10,
"metadataURI": "ipfs://QmXXX..." // If NFT
}
Response 200:
{
"success": true,
"message": "Comic published",
"comic": { ... },
"nft": {
"tokenId": "1",
"contractAddress": "0x...",
"transactionHash": "0x..."
}
}GET /comics?
status=published
&publishType=free|nft
&genre=action,adventure
&sortBy=createdAt
&order=desc
&page=1
&limit=20
Response 200:
{
"success": true,
"comics": [ ... ],
"pagination": {
"page": 1,
"limit": 20,
"total": 150,
"pages": 8
}
}GET /comics/:comicId
Response 200:
{
"success": true,
"comic": {
"_id": "507f...",
"title": "My First Comic",
"description": "...",
"coverImage": "...",
"genre": ["action"],
"chapters": [ ... ],
"totalPages": 20,
"views": 1500,
"likes": 250,
"creator": {
"id": "...",
"username": "johndoe",
"displayName": "John Doe"
},
"nftDetails": { ... }
}
}GET /comics/:comicId/chapters/:chapterNumber/pages
// For free comics: no auth required
// For paid comics: auth required + payment verification
Response 200:
{
"success": true,
"pages": [
{
"pageNumber": 1,
"imageUrl": "https://...",
"ipfsHash": "QmXXX..."
},
...
]
}PUT /comics/:comicId
Authorization: Bearer <token>
Content-Type: application/json
{
"title": "Updated Title",
"description": "New description",
"genre": ["action", "thriller"]
}
Response 200:
{
"success": true,
"comic": { ... }
}DELETE /comics/:comicId
Authorization: Bearer <token>
Response 200:
{
"success": true,
"message": "Comic deleted"
}GET /users/:userId/comics
Authorization: Bearer <token>
Response 200:
{
"success": true,
"comics": [ ... ]
}POST /creator/approve
Authorization: Bearer <ADMIN_TOKEN>
Content-Type: application/json
{
"creatorAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
}
Response 200:
{
"success": true,
"message": "Creator approved",
"transactionHash": "0x..."
}GET /creator/status/:address
Response 200:
{
"success": true,
"isApproved": true
}POST /transactions
Authorization: Bearer <token>
Content-Type: application/json
{
"comicId": "507f...",
"type": "purchase",
"txHash": "0x...",
"tokenId": "1",
"amount": 10.00,
"currency": "HBAR"
}
Response 201:
{
"success": true,
"transaction": { ... }
}GET /transactions?userId=507f...&type=purchase
Response 200:
{
"success": true,
"transactions": [
{
"_id": "...",
"type": "purchase",
"comicId": { ... },
"amount": 10.00,
"currency": "HBAR",
"txHash": "0x...",
"status": "completed",
"createdAt": "2025-01-15T10:30:00Z"
},
...
]
}POST /ipfs/upload
Authorization: Bearer <token>
Content-Type: multipart/form-data
Form Fields:
- coverImage: file
- pages: file[] (array of image files)
- title: string
- description: string
- genre: string (JSON array)
- tags: string (JSON array)
- ageRating: string
- creatorAddress: string
Response 200:
{
"success": true,
"data": {
"metadataURI": "ipfs://QmXXX...",
"coverImageURI": "ipfs://QmYYY...",
"pagesURIs": [
"ipfs://QmZZZ1...",
"ipfs://QmZZZ2...",
...
]
}
}All endpoints follow a consistent error format:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human readable error message"
}
}Common Error Codes:
UNAUTHORIZED: Missing or invalid authenticationFORBIDDEN: Insufficient permissionsNOT_FOUND: Resource not foundVALIDATION_ERROR: Invalid request dataALREADY_EXISTS: Duplicate resourceRATE_LIMIT_EXCEEDED: Too many requestsINTERNAL_ERROR: Server error
src/
├── app/ # Next.js App Router
│ ├── (auth)/ # Auth routes group
│ │ ├── login/
│ │ └── onboarding/
│ ├── (main)/ # Main app routes
│ │ ├── comics/
│ │ │ ├── [id]/ # Comic detail page
│ │ │ └── page.tsx # Comics list
│ │ ├── marketplace/
│ │ └── creator-dashboard/
│ ├── comic-pad/ # Creator tools
│ │ ├── upload-comics/
│ │ ├── my-comics/
│ │ ├── earnings/
│ │ └── settings/
│ ├── layout.tsx
│ └── page.tsx # Home page
│
├── components/
│ ├── ui/ # Reusable UI components
│ │ ├── Button.tsx
│ │ ├── Input.tsx
│ │ ├── Modal.tsx
│ │ └── Card.tsx
│ ├── comic/ # Comic-specific components
│ │ ├── ComicCard.tsx
│ │ ├── ComicReader.tsx
│ │ └── ComicGrid.tsx
│ ├── creator/ # Creator components
│ │ ├── ComicUploader.tsx
│ │ ├── ComicPublisher.tsx
│ │ └── EarningsDashboard.tsx
│ └── layout/ # Layout components
│ ├── Header.tsx
│ ├── Footer.tsx
│ └── Sidebar.tsx
│
├── hooks/ # Custom React hooks
│ ├── useComicMinting.ts
│ ├── usePurchaseComic.ts
│ ├── useAuth.ts
│ └── useWallet.ts
│
├── redux/ # State management
│ ├── slices/
│ │ ├── authSlice.ts
│ │ ├── comicSlice.ts
│ │ └── transactionSlice.ts
│ ├── store.ts
│ └── hooks.ts
│
├── lib/ # Utility libraries
│ ├── ipfs-metadata.ts # IPFS helpers
│ ├── api-client.ts # API wrapper
│ └── utils.ts # General utilities
│
├── contracts/ # Smart contract ABIs
│ └── QuivaComics.ts
│
└── providers/ # Context providers
├── RainbowProvider.tsx
└── ReduxProvider.tsx
Location: src/app/comic-pad/upload-comics/_components/
Features:
- Multi-page upload with drag-and-drop
- Page preview and reordering
- Progress tracking
- File validation (size, format)
- Automatic thumbnail generation
interface ComicUploaderProps {
onPagesUploaded: (pages: File[]) => void;
maxPages?: number;
acceptedFormats?: string[];
}Features:
- Final review before publishing
- Monetization options selection
- IPFS upload progress
- Blockchain minting progress
- Error handling and retry logic
- Success modal with transaction details
interface ComicPublisherProps {
comicData: ComicData;
monetizationData: MonetizationData;
user: User;
onClose: () => void;
}Features:
- Page-by-page navigation
- Zoom controls
- Full-screen mode
- Touch gestures support
- Keyboard shortcuts
- Reading progress tracking
Features:
- NFT listings grid
- Filters and search
- Purchase modal
- Price display in HBAR
- Creator information
- Transaction confirmation
const {
publishComic,
isUploading,
isMinting,
isListing,
uploadProgress,
mintingProgress,
tokenId,
mintError,
isComplete
} = useComicMinting();
// Usage
await publishComic({
comicData,
monetizationData,
user
});Responsibilities:
- Upload assets to IPFS
- Generate metadata
- Check creator approval
- Mint NFT on blockchain
- List on marketplace (optional)
- Create database record
const {
purchaseComic,
isPurchasing,
purchaseError,
purchaseSuccess
} = useComicPurchase();
// Usage
await purchaseComic({
tokenId: BigInt(1),
seller: '0x...',
amount: BigInt(1),
pricePerToken: parseEther('10')
});interface AuthState {
user: User | null;
token: string | null;
isAuthenticated: boolean;
loading: boolean;
error: string | null;
}
// Actions
- login
- logout
- updateProfile
- checkAuthinterface ComicState {
comics: Comic[];
currentComic: Comic | null;
loading: boolean;
error: string | null;
filters: {
genre: string[];
publishType: string;
sortBy: string;
};
}
// Actions
- fetchComics
- fetchComicById
- createComic
- updateComic
- deleteComic
- setFiltersinterface TransactionState {
transactions: Transaction[];
loading: boolean;
error: string | null;
}
// Actions
- createTransaction
- fetchUserTransactions/ (Home)
→ Browse comics
→ Featured content
→ How it works
/comics
→ List all comics
→ Filter and search
/comics/[id]
→ Comic details
→ Read/Purchase
/marketplace
→ NFT listings
→ Buy/Sell
/creator-dashboard
→ Overview
→ Analytics
/comic-pad/upload-comics
→ Upload flow
→ Step-by-step
/comic-pad/my-comics
→ Creator's library
→ Edit/Delete
/comic-pad/earnings
→ Revenue analytics
→ Withdraw
/comic-pad/settings
→ Profile
→ Preferences
/login
→ Email/Wallet auth
/onboarding
→ New user setup
Quiva follows the ERC-1155 metadata standard with additional properties:
{
"name": "Comic Title - Episode 1",
"description": "Comic description",
"image": "ipfs://QmCoverImageHash",
"attributes": [
{
"trait_type": "Creator",
"value": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
},
{
"trait_type": "Genre",
"value": "Action, Adventure"
},
{
"trait_type": "Age Rating",
"value": "Teen (13+)"
},
{
"trait_type": "Page Count",
"value": 20
},
{
"trait_type": "Type",
"value": "Comic Book"
},
{
"trait_type": "Format",
"value": "Digital"
}
],
"properties": {
"pages": [
"ipfs://QmPage1Hash",
"ipfs://QmPage2Hash",
...
],
"genre": ["Action", "Adventure"],
"tags": ["superhero", "manga", "series"],
"ageRating": "teen",
"creator": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
"createdAt": "2025-01-15T10:30:00.000Z",
"pageCount": 20
}
}How it works:
- Creator sets royalty percentage during minting (max 30%)
- Stored in smart contract per tokenId
- Automatically enforced on marketplace sales
- Payment split on each secondary sale:
- Original creator gets royalty %
- Current seller gets (100% - royalty% - platform fee)
- Platform gets platform fee (2.5%)
Example:
Comic minted with 10% royalty
Initial mint: 10 HBAR (100% to creator)
Secondary sale: 20 HBAR
- Creator royalty: 2 HBAR (10%)
- Platform fee: 0.5 HBAR (2.5%)
- Seller receives: 17.5 HBAR (87.5%)
Current Fees:
- Platform Fee: 2.5% on all marketplace transactions
- Minting: Gas fees only (paid by creator)
- Withdrawals: Gas fees only (paid by user)
- Reading: Free for free comics, one-time payment for paid comics
Fee Distribution:
- Platform operations and development
- Future: Creator rewards program
- Future: Community treasury
NFT Supply Models:
-
Limited Edition
- Fixed max supply (e.g., 100 copies)
- Scarcity creates value
- Suitable for collectibles
-
Open Edition
- Large max supply (e.g., 10,000)
- More accessible
- Focus on utility over scarcity
-
1-of-1
- Single unique copy
- Ultra-rare
- Premium pricing
On-Chain (Blockchain):
- Token ownership
- Transfer history
- Listing prices
- Royalty percentages
- Metadata URI pointer
- Contract addresses
Off-Chain (IPFS):
- Comic page images
- Cover images
- NFT metadata JSON
- High-resolution assets
Off-Chain (MongoDB):
- User profiles
- Comic descriptions
- View counts, likes
- Transaction history copy
- Search indexes
- Analytics data
What gets stored on IPFS:
- Comic page images
- Cover images
- NFT metadata JSON files
Why IPFS:
- Decentralized storage
- Content-addressed (permanent links)
- No single point of failure
- Censorship resistant
- Owned by creators forever
Provider: Pinata (Primary)
Gateway: https://gray-tough-elk-417.mypinata.cloud/ipfs/
Alternative Gateways:
https://ipfs.io/ipfs/https://cloudflare-ipfs.com/ipfs/https://gateway.pinata.cloud/ipfs/
// Step 1: Upload individual images
const coverResult = await uploadToIPFS(coverImage);
const coverCID = coverResult.IpfsHash;
const pageResults = await Promise.all(
pages.map(page => uploadToIPFS(page))
);
const pageCIDs = pageResults.map(r => r.IpfsHash);
// Step 2: Create metadata JSON
const metadata = {
name: `${title} - Episode 1`,
description,
image: `ipfs://${coverCID}`,
attributes: [...],
properties: {
pages: pageCIDs.map(cid => `ipfs://${cid}`),
...
}
};
// Step 3: Upload metadata
const metadataResult = await uploadJSONToIPFS(metadata);
const metadataURI = `ipfs://${metadataResult.IpfsHash}`;
// Step 4: Use metadataURI in smart contract
await mintComic(comicId, metadataURI, maxSupply, royalty);// Convert IPFS URI to HTTP URL
function ipfsToHttp(ipfsUri: string): string {
const hash = ipfsUri.replace('ipfs://', '');
return `https://gray-tough-elk-417.mypinata.cloud/ipfs/${hash}`;
}
// Usage
const imageUrl = ipfsToHttp('ipfs://QmXXX...');CID (Content Identifier):
- Cryptographic hash of content
- If content changes, CID changes
- Guarantees content integrity
- Can verify content authenticity
// Verify content hasn't been tampered with
const storedCID = 'QmXXX...';
const fetchedContent = await fetch(ipfsUrl);
const actualCID = await calculateCID(fetchedContent);
if (storedCID === actualCID) {
console.log('Content verified ✓');
} else {
console.error('Content modified!');
}Strategies:
- CDN Caching: Use Pinata dedicated gateway
- Progressive Loading: Load pages on-demand
- Thumbnail Generation: Store low-res previews
- Preloading: Prefetch next page while reading
- Local Cache: Browser cache for repeated views
-
Pay-Per-Read Comics
- One-time payment for lifetime access
- Set your own price
- 97.5% revenue (after 2.5% platform fee)
-
NFT Primary Sales
- Initial mint sales
- 100% revenue to creator (minus gas)
-
NFT Secondary Sales
- Automatic royalties (creator sets %)
- Passive income on resales
- No additional work required
-
Future: Tips/Donations
- Direct fan support
- Optional feature
-
Future: Subscriptions
- Monthly access to all creator's content
- Recurring revenue
- Transaction Fees (2.5%)
- Premium Features (future)
- Featured Listings (future)
- Advertising (future, optional)
Free Comics:
- Claim Free NFT
- Minted by creator generosity
- Great for audience building
Pay-Per-Read:
- Typical range: 1-10 HBAR
- Recommended: 2-5 HBAR
- One-time payment
- Lifetime access
NFT Comics:
- Mint price: 5-50 HBAR typical
- Scarcity factor
- Collectible value
- Investment potential
Reader Purchase (Pay-Per-Read)
↓
Smart Contract receives payment
↓
Platform fee deducted (2.5%)
↓
Remainder to creator's on-chain balance
↓
Creator can withdraw anytime
NFT Purchase (Marketplace)
↓
Smart Contract receives payment
↓
Royalty to original creator (if secondary sale)
↓
Platform fee deducted (2.5%)
↓
Remainder to current seller
↓
NFT transferred to buyer
Process:
- Navigate to Earnings dashboard
- View available balance
- Click "Withdraw Earnings"
- Confirm transaction in wallet
- Gas fees deducted
- Funds sent to wallet address
Minimum Withdrawal: 10 HBAR
Processing Time: Immediate (on-chain)
Fees: Gas only (typically < 0.1 HBAR)
JWT Tokens:
- HS256 algorithm
- 7-day expiration
- Secure secret key (64+ characters)
- Includes role information
- Cannot be forged
Wallet Authentication:
- SIWE (Sign-In with Ethereum) standard
- Cryptographic signature verification
- Nonce prevents replay attacks
- No password storage needed
Middleware Implementation:
// Require authentication
export const requireAuth = (req, res, next) => {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
};
// Require specific role
export const requireRole = (role: Roles) => {
return (req, res, next) => {
if (!req.user || !req.user.role.includes(role)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
};
// Usage
app.post('/comics', requireAuth, requireRole(Roles.CREATOR), createComic);Limits:
- Authentication: 15 requests / 15 minutes
- OTP requests: 1 request / 1 minute
- API endpoints: 60 requests / 1 minute
- Uploads: 50 uploads / 1 hour
- Creator endpoints: 120 requests / 1 minute
Implementation:
import rateLimit from 'express-rate-limit';
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 15,
message: 'Too many authentication attempts'
});
app.use('/api/auth', authLimiter);Validation Rules:
- Username: 3-30 characters, alphanumeric
- Email: Valid email format
- Wallet Address: Valid Ethereum address
- Files: Size limits, allowed types
- Strings: Max length, sanitization
- Numbers: Range validation
Example:
const validateComicInput = (data) => {
if (!data.title || data.title.length > 200) {
throw new Error('Invalid title');
}
if (!data.description || data.description.length > 1000) {
throw new Error('Invalid description');
}
if (!Array.isArray(data.genre) || data.genre.length === 0) {
throw new Error('At least one genre required');
}
};Implemented Protections:
- Reentrancy guard on payable functions
- Access control (only approved creators can mint)
- Integer overflow protection (Solidity 0.8+)
- Input validation on all parameters
- Pausable contract (emergency stop)
- Ownership transfer protection
Audit Status:
- Self-audited ✓
- Community review ✓
- Professional audit: Pending
Sensitive Data:
- Passwords: NEVER stored (wallet-based auth)
- Private keys: NEVER stored on servers
- Email: Encrypted in transit (TLS)
- Personal data: GDPR compliant storage
MongoDB Security:
- Authentication enabled
- Network access whitelist
- Encrypted at rest
- Regular backups
- No sensitive blockchain data in DB
const corsOptions = {
origin: process.env.FRONTEND_URL,
credentials: true,
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));Required:
- Node.js 18+
- MongoDB Atlas account
- Pinata IPFS account
- Hedera wallet with HBAR
- Domain name (optional)
Environment Variables:
Backend (.env):
# Server
PORT=5000
NODE_ENV=production
FRONTEND_URL=https://quiva.io
# Database
MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/quiva
# JWT
JWT_SECRET=your-super-secret-key-64-characters-minimum
# Email
EMAIL_USER=noreply@quiva.io
EMAIL_PASS=your-app-password
# Blockchain
CONTRACT_ADDRESS=0xF5CBD0241D176C6cF35564d2F5b701F74a0756E8
HEDERA_RPC_URL=https://testnet.hashio.io/api
OWNER_PRIVATE_KEY=your-private-key-for-creator-approval
# IPFS
PINATA_API_KEY=your-pinata-api-key
PINATA_SECRET=your-pinata-secret
PINATA_GATEWAY=https://gray-tough-elk-417.mypinata.cloud
# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=15Frontend (.env.local):
NEXT_PUBLIC_API_URL=https://api.quiva.io
NEXT_PUBLIC_CONTRACT_ADDRESS=0xF5CBD0241D176C6cF35564d2F5b701F74a0756E8
NEXT_PUBLIC_HEDERA_CHAIN_ID=296
NEXT_PUBLIC_RAINBOWKIT_PROJECT_ID=your-walletconnect-project-idOption 1: Railway
# 1. Install Railway CLI
npm install -g @railway/cli
# 2. Login
railway login
# 3. Initialize project
railway init
# 4. Add environment variables
railway variables set KEY=value
# 5. Deploy
railway upOption 2: Render
- Connect GitHub repository
- Create new Web Service
- Set build command:
npm install && npm run build - Set start command:
npm start - Add environment variables in dashboard
- Deploy
# 1. Install Vercel CLI
npm install -g vercel
# 2. Login
vercel login
# 3. Deploy
vercel
# Production deployment
vercel --prodOr via Vercel Dashboard:
- Import GitHub repository
- Framework preset: Next.js
- Add environment variables
- Deploy
- Create cluster (M0 Free tier or higher)
- Create database user
- Whitelist IP addresses (0.0.0.0/0 for dynamic IPs)
- Get connection string
- Replace
<password>with actual password - Add to backend env variables
Collections will be auto-created on first use.
- Sign up at pinata.cloud
- Generate API Key (Admin access)
- Create dedicated gateway (optional)
- Add credentials to env variables
Backend API:
api.quiva.io → Your backend deployment
Frontend:
quiva.io → Your frontend deployment
www.quiva.io → Redirect to quiva.io
- Vercel: Auto-provided
- Railway: Auto-provided
- Custom domain: Use Cloudflare for free SSL
Recommended Tools:
- Sentry: Error tracking
- LogRocket: Session replay
- Datadog: Performance monitoring
- MongoDB Atlas: DB monitoring
# Clone repository
# Backend
git clone https://github.com/Saintblade/Quiva-Backend.git
cd backend
# Install dependencies
npm install
# Frontend
git clone https://github.com/Saintblade/Quiva-Frontend.git
cd ../frontend
npm installBackend:
cd backend
npm run dev # Runs on port 5000Frontend:
cd frontend
npm run dev # Runs on port 3000Concurrent (Optional):
# From root directory
npm install -g concurrently
concurrently "cd backend && npm run dev" "cd frontend && npm run dev"Using Remix IDE:
- Go to remix.ethereum.org
- Create new file: QuivaComics.sol
- Paste contract code
- Compile (Solidity 0.8.20)
- Deploy to Hedera Testnet
- Interact with functions
Using Hardhat (Recommended for testing):
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox
npx hardhat init
npx hardhat testNo formal migrations needed (NoSQL flexibility), but:
Schema Updates:
- Update model file
- Deploy backend
- Existing documents auto-update on read/write
For breaking changes:
- Write migration script
- Run against production DB during low traffic
- Test thoroughly in staging first
# Feature branch
git checkout -b feature/new-feature
# Make changes
git add .
git commit -m "feat: add new feature"
# Push to remote
git push origin feature/new-feature
# Create Pull Request
# Review and mergeBranch Naming:
feature/- New featuresbugfix/- Bug fixeshotfix/- Critical production fixesrefactor/- Code improvements
Commit Messages:
feat:- New featurefix:- Bug fixdocs:- Documentationstyle:- Formattingrefactor:- Code restructuringtest:- Testschore:- Maintenance
Solution:
# Call approve endpoint from backend
curl -X POST http://localhost:5000/api/creator/approve \
-H "Content-Type: application/json" \
-d '{"creatorAddress": "0x..."}'
# Or check status
curl http://localhost:5000/api/creator/status/0x...Possible causes:
- Invalid Pinata credentials
- File too large (>100MB)
- Network timeout
- Rate limit exceeded
Solutions:
- Verify API keys
- Compress images
- Increase timeout
- Check Pinata dashboard for limits
Solutions:
- Ensure correct chain ID (296)
- Add Hedera Testnet to wallet manually
- Clear browser cache
- Try different wallet
Add Hedera Testnet manually:
Network Name: Hedera Testnet
RPC URL: https://testnet.hashio.io/api
Chain ID: 296
Currency Symbol: HBAR
Block Explorer: https://hashscan.io/testnet
Possible causes:
- Insufficient gas
- Contract function reverted
- Invalid parameters
- Network congestion
Solutions:
- Check wallet has enough HBAR
- Verify all parameters
- Check contract is not paused
- Wait and retry
Backend Debugging:
# Enable verbose logging
DEBUG=* npm run dev
# Check specific module
DEBUG=express:* npm run dev
# Database query logging
MONGODB_LOG_LEVEL=debug npm run devFrontend Debugging:
// Enable Redux DevTools
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
reducer: rootReducer,
devTools: process.env.NODE_ENV !== 'production'
});
// Log all Wagmi events
const { connector } = useAccount({
onConnect: (data) => console.log('Connected', data),
onDisconnect: () => console.log('Disconnected')
});Smart Contract Debugging:
// Add events for debugging
event Debug(string message, uint256 value);
function someFunction() public {
emit Debug("Checkpoint 1", value);
// ... code ...
emit Debug("Checkpoint 2", newValue);
}Slow page loads:
- Enable image optimization (Next.js)
- Use CDN for IPFS gateway
- Implement lazy loading
- Add loading skeletons
Slow database queries:
- Add indexes to frequently queried fields
- Use projection (select only needed fields)
- Implement pagination
- Cache frequent queries
High gas fees:
- Batch transactions when possible
- Use Hedera Testnet (low fees)
- Optimize contract code
- Wait for lower network activity
- Hedera Docs: https://docs.hedera.com
- Wagmi Docs: https://wagmi.sh
- Next.js Docs: https://nextjs.org/docs
- MongoDB Docs: https://docs.mongodb.com
- IPFS Docs: https://docs.ipfs.tech
- Discord: discord.gg/quiva (coming soon)
- Twitter: @quivacomics (coming soon)
- GitHub: github.com/quiva-comics
- Email: support@quiva.io
We welcome contributions! Please see:
- CONTRIBUTING.md (coming soon)
- CODE_OF_CONDUCT.md (coming soon)
This documentation is proprietary to Quiva Platform. Source code license: TBD
HBAR: Native cryptocurrency of Hedera network
IPFS: InterPlanetary File System - decentralized storage
CID: Content Identifier - unique hash for IPFS content
NFT: Non-Fungible Token - unique digital asset
ERC-1155: Multi-token standard supporting both fungible and non-fungible tokens
Gas: Transaction fee on blockchain
Royalty: Percentage of sales going to original creator
Mint: Create a new NFT on blockchain
Wallet: Software for managing blockchain assets
Smart Contract: Self-executing code on blockchain
OTP: One-Time Password for authentication
JWT: JSON Web Token for session management
| Code | Status | Meaning |
|---|---|---|
| 200 | OK | Request successful |
| 201 | Created | Resource created |
| 204 | No Content | Success, no response body |
| 400 | Bad Request | Invalid input |
| 401 | Unauthorized | Authentication required |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Resource already exists |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error |
| 503 | Service Unavailable | Temporary outage |
Users Collection:
db.users.createIndex({ email: 1 }, { unique: true, sparse: true })
db.users.createIndex({ walletAddress: 1 }, { unique: true, sparse: true })
db.users.createIndex({ username: 1 }, { unique: true })
db.users.createIndex({ "creatorProfile.verified": 1 })Comics Collection:
db.comics.createIndex({ creatorId: 1 })
db.comics.createIndex({ status: 1 })
db.comics.createIndex({ publishType: 1 })
db.comics.createIndex({ genre: 1 })
db.comics.createIndex({ createdAt: -1 })
db.comics.createIndex({ publishedAt: -1 })
db.comics.createIndex({ "nftDetails.tokenId": 1 })
db.comics.createIndex({ title: "text", description: "text" })Transactions Collection:
db.transactions.createIndex({ userId: 1 })
db.transactions.createIndex({ comicId: 1 })
db.transactions.createIndex({ txHash: 1 }, { unique: true })
db.transactions.createIndex({ type: 1 })
db.transactions.createIndex({ status: 1 })
db.transactions.createIndex({ createdAt: -1 })End of Documentation
This documentation is maintained by the Quiva development team and is updated regularly. Last update: October 30, 2025