Skip to main content

Development Guide

Comprehensive development guide for the Toto ecosystem - from local setup to production deployment.

πŸ“˜ Project-Specific Setup: For detailed setup instructions for individual projects, see:

πŸš€ Quick Start​

Prerequisites​

  • Node.js: Version 18 or higher
  • npm: Latest version
  • Git: Version control system
  • Firebase CLI: For deployment and configuration
  • Code Editor: VS Code recommended

Environment Setup​

# Install Firebase CLI
npm install -g firebase-tools

# Login to Firebase
firebase login

# Clone repositories
git clone <toto-repo>
git clone <toto-bo-repo>
git clone <toto-ai-hub-repo>
git clone <toto-wallet-repo>

πŸ— Project Structure​

Repository Organization​

toto-ecosystem/
β”œβ”€β”€ toto/ # Main application
β”œβ”€β”€ toto-bo/ # Backoffice
β”œβ”€β”€ toto-ai-hub/ # AI system
β”œβ”€β”€ toto-wallet/ # Payment system
└── toto-docs/ # Documentation

Technology Stack​

  • Frontend: Next.js 15 with TypeScript
  • Backend: Next.js API Routes
  • Database: Firestore
  • Deployment: Firebase App Hosting
  • Authentication: Firebase Auth + NextAuth.js
  • AI: Multi-agent AI system
  • Payments: Stellar blockchain

πŸ”§ Local Development Setup​

For project-specific setup instructions, see:

Development Servers​

Main App (toto-app):

cd toto-app
npm run dev # Runs on http://localhost:4000

Backoffice (toto-bo):

cd toto-bo
npm run dev # Runs on http://localhost:5000

πŸ§ͺ Testing Setup​

Unit Testing​

# Run unit tests
npm run test

# Run tests with coverage
npm run test:coverage

# Run tests in watch mode
npm run test:watch

Integration Testing​

# Run integration tests
npm run test:integration

# Run API tests
npm run test:api

E2E Testing​

# Run E2E tests
npm run test:e2e

# Run E2E tests in headless mode
npm run test:e2e:headless

πŸ”§ Development Tools​

Code Quality​

# Lint code
npm run lint

# Fix linting issues
npm run lint:fix

# Type checking
npm run type-check

# Format code
npm run format

Database Management​

# Start Firestore emulator
firebase emulators:start --only firestore

# Export data
firebase firestore:export ./backup

# Import data
firebase firestore:import ./backup

API Testing​

# Test API endpoints
npm run test:api

# Test with Postman collection
newman run postman_collection.json

πŸš€ Deployment Workflow​

Development Environment​

# Build for development
npm run build:dev

# Deploy to development
firebase use development
firebase deploy

Staging Environment​

# Build for staging
npm run build:staging

# Deploy to staging
firebase use staging
firebase deploy

Production Environment​

# Build for production
npm run build:prod

# Deploy to production
firebase use production
firebase deploy

πŸ“Š Monitoring & Debugging​

Logging​

// Structured logging
import { logger } from '@/lib/logger';

logger.info('User action', {
userId: 'user-123',
action: 'case_created',
caseId: 'case-456'
});

logger.error('Error occurred', {
error: error.message,
stack: error.stack,
context: 'api/cases'
});

Performance Monitoring​

// Performance tracking
import { performance } from 'firebase/apphosting';

const trace = performance.trace('api_request');
trace.start();

// ... API logic

trace.stop();

Error Tracking​

// Error monitoring
import { captureException } from '@sentry/nextjs';

try {
// ... code that might fail
} catch (error) {
captureException(error, {
tags: {
component: 'cases-api',
action: 'create-case'
}
});
throw error;
}

πŸ” Security Best Practices​

Authentication​

// JWT token validation
import { verifyIdToken } from 'firebase-admin/auth';

const validateToken = async (token: string) => {
try {
const decodedToken = await verifyIdToken(token);
return decodedToken;
} catch (error) {
throw new Error('Invalid token');
}
};

Authorization​

// Role-based access control
const canAccessResource = (user: User, resource: string, action: string) => {
const permissions = getUserPermissions(user.role);
return permissions.includes(`${action}_${resource}`);
};

Input Validation​

// Request validation
import { z } from 'zod';

const createCaseSchema = z.object({
name: z.string().min(1).max(100),
description: z.string().min(1).max(1000),
guardianId: z.string().uuid(),
donationGoal: z.number().positive()
});

const validateCreateCase = (data: unknown) => {
return createCaseSchema.parse(data);
};

πŸ”„ Database Management​

Schema Design​

// Firestore schema
interface Case {
id: string;
name: string;
description: string;
status: 'active' | 'urgent' | 'completed';
guardianId: string;
donationGoal: number;
donationsReceived: number;
createdAt: Timestamp;
updatedAt: Timestamp;
}

interface User {
id: string;
email: string;
name: string;
role: 'user' | 'guardian' | 'admin';
phone?: string;
createdAt: Timestamp;
}

Indexing Strategy​

// Firestore indexes
// Collection: cases
// Fields: status (Ascending), createdAt (Descending)
// Query: where('status', '==', 'active').orderBy('createdAt', 'desc')

// Collection: users
// Fields: role (Ascending), createdAt (Descending)
// Query: where('role', '==', 'guardian').orderBy('createdAt', 'desc')

Data Migration​

// Migration script
const migrateUserRoles = async () => {
const usersRef = db.collection('users');
const snapshot = await usersRef.get();

const batch = db.batch();

snapshot.docs.forEach(doc => {
const user = doc.data();
if (!user.role) {
batch.update(doc.ref, { role: 'user' });
}
});

await batch.commit();
};

πŸ§ͺ Testing Strategies​

Unit Tests​

// Example unit test
import { render, screen } from '@testing-library/react';
import { CaseCard } from '@/components/CaseCard';

describe('CaseCard', () => {
it('renders case information correctly', () => {
const caseData = {
id: 'case-123',
name: 'Max the Dog',
description: 'Rescue case for Max',
status: 'active'
};

render(<CaseCard case={caseData} />);

expect(screen.getByText('Max the Dog')).toBeInTheDocument();
expect(screen.getByText('Rescue case for Max')).toBeInTheDocument();
});
});

Integration Tests​

// Example integration test
import { createMocks } from 'node-mocks-http';
import handler from '@/pages/api/cases';

describe('/api/cases', () => {
it('returns cases list', async () => {
const { req, res } = createMocks({
method: 'GET',
query: { limit: '10' }
});

await handler(req, res);

expect(res._getStatusCode()).toBe(200);
expect(JSON.parse(res._getData())).toHaveProperty('cases');
});
});

E2E Tests​

// Example E2E test
import { test, expect } from '@playwright/test';

test('user can create a case', async ({ page }) => {
await page.goto('/cases/new');

await page.fill('[data-testid="case-name"]', 'Max the Dog');
await page.fill('[data-testid="case-description"]', 'Rescue case for Max');
await page.click('[data-testid="submit-button"]');

await expect(page).toHaveURL(/\/cases\/\d+/);
await expect(page.locator('h1')).toContainText('Max the Dog');
});

πŸ“š Documentation​

Code Documentation​

/**
* Creates a new case in the system
* @param caseData - The case data to create
* @param userId - The ID of the user creating the case
* @returns Promise<Case> - The created case
* @throws {ValidationError} - If case data is invalid
* @throws {AuthorizationError} - If user lacks permission
*/
const createCase = async (caseData: CreateCaseData, userId: string): Promise<Case> => {
// Implementation
};

API Documentation​

/**
* @api {post} /api/cases Create Case
* @apiName CreateCase
* @apiGroup Cases
* @apiVersion 1.0.0
*
* @apiParam {String} name Case name
* @apiParam {String} description Case description
* @apiParam {String} guardianId Guardian ID
* @apiParam {Number} donationGoal Donation goal amount
*
* @apiSuccess {Object} case Created case object
* @apiSuccess {String} case.id Case ID
* @apiSuccess {String} case.name Case name
*
* @apiError {Object} 400 Validation error
* @apiError {Object} 401 Unauthorized
* @apiError {Object} 403 Forbidden
*/