Skip to main content

Prerequisites

Before you begin, ensure you have the following installed:
  • Python 3.11+ - Backend runtime
  • Node.js 18+ - Frontend runtime (if working on client)
  • Redis - Session management and caching
  • Africa’s Talking Account - Sandbox or production credentials
  • ngrok - For local webhook testing (required for Voice/SMS/USSD)

Project Structure

voicepact/
├── server/              # FastAPI backend
   ├── app/
   ├── api/        # API routes
   ├── core/       # Configuration
   ├── models/     # Database models
   └── services/   # Business logic
   ├── tests/          # Test suite
   ├── etl/            # Analytics pipeline
   ├── main.py         # Application entry
   └── requirements.txt
└── client/             # Next.js frontend (in development)

Initial Setup

1. Clone the Repository

git clone https://github.com/mutuiris/voicepact.git
cd voicepact

2. Backend Setup

Create Virtual Environment

cd server
python -m venv venv

# Activate virtual environment
# On Linux/Mac:
source venv/bin/activate

# On Windows:
venv\Scripts\activate

Install Dependencies

pip install -r requirements.txt
Key dependencies include:
  • fastapi - Web framework
  • uvicorn - ASGI server
  • africastalking - Africa’s Talking SDK
  • sqlalchemy - Database ORM
  • redis - Caching
  • pydantic-settings - Configuration management

3. Environment Configuration

The application uses pydantic-settings for configuration management. Create a .env file in the server/ directory:
# server/.env

# Application
APP_NAME=VoicePact
ENVIRONMENT=development
DEBUG=true

# Africa's Talking API
AT_USERNAME=sandbox
AT_API_KEY=your_api_key_here
AT_VOICE_NUMBER=+254XXXXXXXXX
AT_PAYMENT_PRODUCT_NAME=VoicePact
AT_USSD_SERVICE_CODE=*483#

# Database
DATABASE_URL=sqlite:///./voicepact.db
DATABASE_ECHO=false

# Redis
REDIS_URL=redis://localhost:6379/0
REDIS_MAX_CONNECTIONS=20

# Security
SECRET_KEY=your-secret-key-here
SIGNATURE_PRIVATE_KEY=your-ed25519-private-key-here

# Webhooks (set after starting ngrok)
WEBHOOK_BASE_URL=https://your-ngrok-url.ngrok.io

# Voice Processing
WHISPER_MODEL_SIZE=small
MAX_AUDIO_DURATION=1200
MAX_AUDIO_FILE_SIZE=52428800

# Logging
LOG_LEVEL=INFO
LOG_FORMAT=%(asctime)s - %(name)s - %(levelname)s - %(message)s
Secret keys can be generated using python -c "import secrets; print(secrets.token_urlsafe(32))"

4. Start Redis

Redis is required for caching and session management:
# On Linux/Mac with Docker:
docker run -d -p 6379:6379 redis:alpine

# Or install locally:
# Ubuntu/Debian:
sudo apt-get install redis-server
sudo systemctl start redis

# macOS:
brew install redis
brew services start redis
Verify Redis is running:
redis-cli ping
# Should return: PONG

5. Initialize Database

The application uses SQLite for development (PostgreSQL recommended for production):
# Database is automatically initialized on first run
python main.py
The database file voicepact.db will be created with WAL mode enabled for concurrent access.

6. Frontend Setup (Optional)

The frontend is currently using the default Next.js template and is not yet fully implemented.
cd client
npm install
cp .env.local.example .env.local

# Edit .env.local with your settings:
NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
NEXT_PUBLIC_WEBSOCKET_BASE=ws://localhost:8000

npm run dev

Running the Application

Start the Backend Server

cd server
source venv/bin/activate
uvicorn main:app --reload --port 8000
The server will start with:

Development Server Features

The FastAPI server includes:
  1. Auto-reload: Code changes trigger automatic restart
  2. Debug mode: Detailed error messages and stack traces
  3. CORS enabled: Configured for local frontend development
  4. Swagger UI: Interactive API documentation at /docs
  5. Async support: Non-blocking I/O for external API calls

Verify Installation

Test the server is running correctly:
# Check health endpoint
curl http://localhost:8000/health

# Check application info
curl http://localhost:8000/info

# Check SMS service status
curl http://localhost:8000/api/v1/sms/status

Development Workflow

Code Organization

The codebase follows FastAPI best practices:
server/app/
├── api/v1/
│   ├── endpoints/
│   │   ├── voice.py      # Voice recording endpoints
│   │   ├── sms.py        # SMS endpoints
│   │   ├── contracts.py  # Contract management
│   │   ├── payments.py   # Escrow/payment endpoints
│   │   └── ussd.py       # USSD session handler
│   └── api.py            # Router aggregation
├── core/
│   ├── config.py         # Settings with pydantic
│   └── database.py       # Database session management
├── models/               # SQLAlchemy models
└── services/             # Business logic layer

Configuration System

Settings are managed via server/app/core/config.py:Settings using pydantic-settings:
from app.core.config import get_settings

settings = get_settings()  # Cached singleton

# Access configuration
print(settings.at_username)
print(settings.environment)
print(settings.is_development)  # Computed property

# Access secrets safely
api_key = settings.get_secret_value('at_api_key')
Settings are cached with @lru_cache() for performance. Changes to .env require a server restart.

Database Access

The application uses async SQLAlchemy:
from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db

@router.post("/example")
async def example_endpoint(db: AsyncSession = Depends(get_db)):
    # Database operations
    await db.commit()

Adding New Endpoints

  1. Create endpoint in server/app/api/v1/endpoints/
  2. Define request/response models with Pydantic
  3. Add router to server/app/api/v1/api.py
  4. Test with /docs interactive UI
Example:
# server/app/api/v1/endpoints/example.py
from fastapi import APIRouter
from pydantic import BaseModel

router = APIRouter()

class ExampleRequest(BaseModel):
    name: str

class ExampleResponse(BaseModel):
    message: str

@router.post("/example", response_model=ExampleResponse)
async def create_example(request: ExampleRequest):
    return ExampleResponse(message=f"Hello {request.name}")

Debugging Tips

Enable Debug Logging

# In .env
DEBUG=true
LOG_LEVEL=DEBUG
This enables:
  • Detailed stack traces in responses
  • SQL query logging (with DATABASE_ECHO=true)
  • Verbose application logs

Common Issues

Symptom: Application fails to start with Redis connection errorSolution:
# Check Redis is running
redis-cli ping

# If not installed:
docker run -d -p 6379:6379 redis:alpine

# Verify connection string in .env
REDIS_URL=redis://localhost:6379/0
Symptom: database is locked error with SQLiteSolution: SQLite is configured with WAL mode, but ensure:
  • Only one server instance is running
  • Database file has write permissions
  • No manual SQLite connections are open
Symptom: Module not found errorsSolution:
# Ensure virtual environment is activated
source venv/bin/activate

# Reinstall dependencies
pip install -r requirements.txt

# Verify Python version
python --version  # Should be 3.11+
Symptom: SMS or Voice calls failSolution:
  • Verify AT_API_KEY is set correctly in .env
  • Check API key has appropriate permissions
  • For voice/webhooks, ensure ngrok is configured (see ngrok setup guide)
# Test SMS service
curl http://localhost:8000/api/v1/sms/status

Using the Interactive Docs

FastAPI provides Swagger UI at http://localhost:8000/docs:
  1. Navigate to any endpoint
  2. Click “Try it out”
  3. Fill in request parameters
  4. Execute and view response
  5. See generated curl command

Hot Reload

The development server supports hot reload:
# Changes to these files trigger reload:
- *.py files in server/
- Configuration in .env (requires restart)

# These do NOT trigger reload:
- Static assets
- Database files
- External configuration
To restart manually:
# Stop server (Ctrl+C)
# Start again
uvicorn main:app --reload --port 8000

Performance Considerations

Development vs Production

Development mode includes:
  • ✅ Debug mode enabled
  • ✅ Auto-reload on code changes
  • ✅ Detailed error messages
  • ✅ API documentation enabled
  • ✅ SQLite database
  • ✅ Verbose logging
Production mode should use:
  • ❌ Debug mode disabled
  • ❌ No auto-reload
  • ❌ Generic error messages
  • ❌ API docs disabled
  • ✅ PostgreSQL database
  • ✅ Error-level logging only

Local Resource Usage

  • Memory: ~200MB baseline (increases with Whisper model size)
  • CPU: Low idle, spikes during audio processing
  • Disk: ~50MB + database size
  • Network: Depends on Africa’s Talking API usage

Next Steps

Testing Guide

Learn how to write and run tests for VoicePact

ngrok Setup

Configure ngrok for webhook testing

API Reference

Explore the complete API documentation

Architecture

Understand the system architecture

Build docs developers (and LLMs) love