From b2cbf9b04b0c5a5a060f564555711bedab220d5f Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:20:23 +0100 Subject: [PATCH 01/15] docs: add deployment guide --- DEPLOYMENT.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 DEPLOYMENT.md diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..33562c5 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,51 @@ +# Deployment Guide + +## Prerequisites + +- Node.js 18+ +- npm or yarn +- Git +- Vercel account (for frontend) +- Alchemy/Infura account (for Base) +- The Graph account (for indexing) + +## Environment Variables + +```env +NEXT_PUBLIC_RPC_URL=your_base_rpc_url +NEXT_PUBLIC_CONTRACT_ADDRESS=your_contract_address +NEXT_PUBLIC_GRAPH_URL=your_subgraph_url +``` + +## Frontend Deployment + +### Vercel (Recommended) + +```bash +npm i -g vercel +vercel +``` + +### Build for Production + +```bash +npm run build +npm start +``` + +## Smart Contract Deployment + +### Using Foundry + +```bash +cd contracts +forge build +forge create --rpc-url $RPC_URL --private-key $PRIVATE_KEY src/TriviaGame.sol:TriviaGame +``` + +## Subgraph Deployment + +```bash +cd subgraph +graph deploy --product hosted-service your-username/reui +``` From 947faf302551d6354b49a5204200916cd4ea2859 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:20:41 +0100 Subject: [PATCH 02/15] docs: add API documentation --- API.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 API.md diff --git a/API.md b/API.md new file mode 100644 index 0000000..6225f89 --- /dev/null +++ b/API.md @@ -0,0 +1,50 @@ +# API Documentation + +## Endpoints + +### GET /api/questions + +Fetch questions for a game session. + +**Query Parameters:** +- `category` (optional): Filter by category +- `difficulty` (optional): easy, medium, hard, expert +- `limit` (optional): Number of questions (default: 10) + +**Response:** +```json +{ + "questions": [ + { + "id": "q1", + "question": "What is the capital of France?", + "options": ["Paris", "London", "Berlin", "Madrid"], + "correctAnswer": 0, + "category": "general", + "difficulty": "easy" + } + ] +} +``` + +### POST /api/scores + +Submit game score. + +**Body:** +```json +{ + "address": "0x...", + "score": 8500, + "category": "science", + "difficulty": "medium" +} +``` + +### GET /api/leaderboard + +Get top scores. + +**Query Parameters:** +- `limit` (optional): Number of entries (default: 10) +- `category` (optional): Filter by category From add0e63494d25f0840cc0aaa9153ce94f3f924d4 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:21:01 +0100 Subject: [PATCH 03/15] feat(api): add api response types --- frontend/src/types/apiResponse.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 frontend/src/types/apiResponse.ts diff --git a/frontend/src/types/apiResponse.ts b/frontend/src/types/apiResponse.ts new file mode 100644 index 0000000..74e9ec6 --- /dev/null +++ b/frontend/src/types/apiResponse.ts @@ -0,0 +1,13 @@ +export interface ApiResponse { + success: boolean; + data?: T; + error?: string; +} + +export interface PaginatedResponse { + items: T[]; + total: number; + page: number; + limit: number; + hasMore: boolean; +} From d46088d76fa835cc5a2331328065d6be03198563 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:21:26 +0100 Subject: [PATCH 04/15] feat(api): add api client --- frontend/src/lib/apiClient.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 frontend/src/lib/apiClient.ts diff --git a/frontend/src/lib/apiClient.ts b/frontend/src/lib/apiClient.ts new file mode 100644 index 0000000..5eed122 --- /dev/null +++ b/frontend/src/lib/apiClient.ts @@ -0,0 +1,19 @@ +import { ApiResponse, PaginatedResponse } from '@/types/apiResponse'; + +const API_BASE = process.env.NEXT_PUBLIC_API_URL || '/api'; + +export const apiClient = { + async get(endpoint: string): Promise> { + const res = await fetch(`${API_BASE}${endpoint}`); + return res.json(); + }, + + async post(endpoint: string, data: any): Promise> { + const res = await fetch(`${API_BASE}${endpoint}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }); + return res.json(); + }, +}; From a62787ab1c1f1d774225af70acbd6414882d2b27 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:21:45 +0100 Subject: [PATCH 05/15] feat(config): add environment configuration --- frontend/src/lib/env.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 frontend/src/lib/env.ts diff --git a/frontend/src/lib/env.ts b/frontend/src/lib/env.ts new file mode 100644 index 0000000..2e4825b --- /dev/null +++ b/frontend/src/lib/env.ts @@ -0,0 +1,13 @@ +export interface EnvConfig { + rpcUrl: string; + contractAddress: string; + graphUrl: string; + network: 'base-mainnet' | 'base-sepolia'; +} + +export const getEnvConfig = (): EnvConfig => ({ + rpcUrl: process.env.NEXT_PUBLIC_RPC_URL || '', + contractAddress: process.env.NEXT_PUBLIC_CONTRACT_ADDRESS || '', + graphUrl: process.env.NEXT_PUBLIC_GRAPH_URL || '', + network: (process.env.NEXT_PUBLIC_NETWORK as EnvConfig['network']) || 'base-sepolia', +}); From b05d5d4daca67c1b08c6170daf337f647cd4332c Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:22:02 +0100 Subject: [PATCH 06/15] feat(api): add api error handling --- frontend/src/lib/apiError.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 frontend/src/lib/apiError.ts diff --git a/frontend/src/lib/apiError.ts b/frontend/src/lib/apiError.ts new file mode 100644 index 0000000..5ba8a40 --- /dev/null +++ b/frontend/src/lib/apiError.ts @@ -0,0 +1,15 @@ +import { createError } from './errorUtils'; + +export class ApiError extends Error { + constructor(message: string, public status: number = 500) { + super(message); + this.name = 'ApiError'; + } +} + +export const handleApiError = (error: any): never => { + if (error.response) { + throw new ApiError(error.response.data.message, error.response.status); + } + throw new ApiError(error.message || 'Network error'); +}; From 7a53edc10382231dacbe256840b9e12325ebb102 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:22:20 +0100 Subject: [PATCH 07/15] feat(validation): add input validators --- frontend/src/lib/validators.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 frontend/src/lib/validators.ts diff --git a/frontend/src/lib/validators.ts b/frontend/src/lib/validators.ts new file mode 100644 index 0000000..10294ee --- /dev/null +++ b/frontend/src/lib/validators.ts @@ -0,0 +1,11 @@ +export const validateAddress = (address: string): boolean => { + return /^0x[a-fA-F0-9]{40}$/.test(address); +}; + +export const validateEmail = (email: string): boolean => { + return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); +}; + +export const validateScore = (score: number): boolean => { + return score >= 0 && score <= 1000000; +}; From 7c24080539c789aac3efabab4eb8ebe894f34b1a Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:22:36 +0100 Subject: [PATCH 08/15] feat(hooks): add useDebounce hook --- frontend/src/hooks/useDebounce.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 frontend/src/hooks/useDebounce.ts diff --git a/frontend/src/hooks/useDebounce.ts b/frontend/src/hooks/useDebounce.ts new file mode 100644 index 0000000..62b60c9 --- /dev/null +++ b/frontend/src/hooks/useDebounce.ts @@ -0,0 +1,12 @@ +import { useState, useEffect } from 'react'; + +export const useDebounce = (value: T, delay: number = 500): T => { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => setDebouncedValue(value), delay); + return () => clearTimeout(timer); + }, [value, delay]); + + return debouncedValue; +}; From caba291eb9040daf1e15cd7e9c02b9cacc22b020 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:22:53 +0100 Subject: [PATCH 09/15] feat(hooks): add useLocalStorage hook --- frontend/src/hooks/useLocalStorage.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 frontend/src/hooks/useLocalStorage.ts diff --git a/frontend/src/hooks/useLocalStorage.ts b/frontend/src/hooks/useLocalStorage.ts new file mode 100644 index 0000000..322bd2c --- /dev/null +++ b/frontend/src/hooks/useLocalStorage.ts @@ -0,0 +1,16 @@ +import { useState, useEffect } from 'react'; + +export const useLocalStorage = (key: string, initialValue: T): [T, (value: T) => void] => { + const [storedValue, setStoredValue] = useState(() => { + if (typeof window === 'undefined') return initialValue; + const item = window.localStorage.getItem(key); + return item ? JSON.parse(item) : initialValue; + }); + + const setValue = (value: T) => { + setStoredValue(value); + window.localStorage.setItem(key, JSON.stringify(value)); + }; + + return [storedValue, setValue]; +}; From 1e58de9ac31ffc5ff3e42e94831a31db9214c266 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:23:12 +0100 Subject: [PATCH 10/15] feat(utils): add formatters utility --- frontend/src/utils/formatters.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 frontend/src/utils/formatters.ts diff --git a/frontend/src/utils/formatters.ts b/frontend/src/utils/formatters.ts new file mode 100644 index 0000000..8756b53 --- /dev/null +++ b/frontend/src/utils/formatters.ts @@ -0,0 +1,12 @@ +export const formatAddress = (address: string): string => { + if (!address) return ''; + return `${address.slice(0, 6)}...${address.slice(-4)}`; +}; + +export const formatNumber = (num: number): string => { + return new Intl.NumberFormat().format(num); +}; + +export const formatCurrency = (amount: number, currency = 'USD'): string => { + return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount); +}; From ed6dde1fc7a0e22bf4805b5a5019f65d22863292 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:23:33 +0100 Subject: [PATCH 11/15] feat(utils): add string utilities --- frontend/src/utils/stringUtils.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 frontend/src/utils/stringUtils.ts diff --git a/frontend/src/utils/stringUtils.ts b/frontend/src/utils/stringUtils.ts new file mode 100644 index 0000000..c4fe50d --- /dev/null +++ b/frontend/src/utils/stringUtils.ts @@ -0,0 +1,12 @@ +export const truncateText = (text: string, maxLength: number): string => { + if (text.length <= maxLength) return text; + return text.slice(0, maxLength) + '...'; +}; + +export const capitalize = (str: string): string => { + return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); +}; + +export const slugify = (text: string): string => { + return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, ''); +}; From bebf27fb4b8862c1d833ff207f1b76d4e1c016e3 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:23:49 +0100 Subject: [PATCH 12/15] feat(utils): add async utilities --- frontend/src/utils/asyncUtils.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 frontend/src/utils/asyncUtils.ts diff --git a/frontend/src/utils/asyncUtils.ts b/frontend/src/utils/asyncUtils.ts new file mode 100644 index 0000000..c8afcb2 --- /dev/null +++ b/frontend/src/utils/asyncUtils.ts @@ -0,0 +1,17 @@ +export const delay = (ms: number): Promise => new Promise(resolve => setTimeout(resolve, ms)); + +export const retry = async (fn: () => Promise, retries = 3, delayMs = 1000): Promise => { + try { + return await fn(); + } catch (error) { + if (retries <= 0) throw error; + await delay(delayMs); + return retry(fn, retries - 1, delayMs * 2); + } +}; + +export const chunk = (array: T[], size: number): T[][] => { + return Array.from({ length: Math.ceil(array.length / size) }, (_, i) => + array.slice(i * size, i * size + size) + ); +}; From b0d76adc60f057d6ebd17c4daf15ebd29124a562 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:24:06 +0100 Subject: [PATCH 13/15] feat(config): add theme configuration --- frontend/src/constants/theme.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 frontend/src/constants/theme.ts diff --git a/frontend/src/constants/theme.ts b/frontend/src/constants/theme.ts new file mode 100644 index 0000000..804589e --- /dev/null +++ b/frontend/src/constants/theme.ts @@ -0,0 +1,26 @@ +export interface Theme { + colors: { + primary: string; + secondary: string; + background: string; + text: string; + }; +} + +export const lightTheme: Theme = { + colors: { + primary: '#8B5CF6', + secondary: '#EC4899', + background: '#FFFFFF', + text: '#1F2937', + }, +}; + +export const darkTheme: Theme = { + colors: { + primary: '#8B5CF6', + secondary: '#EC4899', + background: '#1F2937', + text: '#FFFFFF', + }, +}; From 8be7f78250462e93342472ec610a32ef4b8ad9a3 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:24:27 +0100 Subject: [PATCH 14/15] docs: add security best practices --- SECURITY.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..ab390cf --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,25 @@ +# Security Best Practices + +## Smart Contracts Open + +- UseZeppelin libraries +- Implement access control +- Validate all inputs +- Use SafeMath for arithmetic +- Emit events for all state changes + +## Frontend + +- Never expose private keys +- Validate user inputs +- Use HTTPS only +- Implement rate limiting +- Sanitize user-generated content + +## General + +- Keep dependencies updated +- Use environment variables for secrets +- Implement proper error handling +- Log security events +- Regular security audits From 7a22c911d7e0980b8431e08237d412e644576463 Mon Sep 17 00:00:00 2001 From: diiabblo Date: Fri, 13 Feb 2026 03:24:47 +0100 Subject: [PATCH 15/15] docs: add performance optimization guide --- PERFORMANCE.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 PERFORMANCE.md diff --git a/PERFORMANCE.md b/PERFORMANCE.md new file mode 100644 index 0000000..8dfea1a --- /dev/null +++ b/PERFORMANCE.md @@ -0,0 +1,30 @@ +# Performance Optimization Guide + +## Frontend + +### Code Splitting +- Use dynamic imports for routes +- Lazy load heavy components +- Implement virtualization for lists + +### Caching +- Use SWR or React Query for data fetching +- Implement proper cache strategies +- Use service workers for offline support + +### Bundle Optimization +- Analyze bundle with next/bundle-analyzer +- Remove unused code +- Compress assets + +## Backend + +### Database +- Index frequently queried fields +- Use pagination for large datasets +- Implement caching layer + +### API +- Rate limiting +- Request validation +- Response compression