Skip to content

Customization for Developers

🎯 Overview

This guide helps developers customize ALwrity for specific needs. You'll learn how to extend functionality, create custom components, integrate with external systems, and tailor the platform to your requirements.

🚀 What You'll Achieve

Custom Development

  • Feature Extensions: Extend existing features and functionality
  • Custom Components: Create custom UI components and interfaces
  • API Extensions: Extend API endpoints and functionality
  • Integration Development: Develop custom integrations

Platform Tailoring

  • Brand Customization: Customize branding and user interface
  • Workflow Customization: Customize workflows and processes
  • Business Logic: Implement custom business logic
  • Data Models: Extend data models and schemas

📋 Customization Framework

Extension Points

Backend Extensions: 1. API Endpoints: Add custom API endpoints 2. Services: Extend or create new services 3. Models: Add custom data models 4. Middleware: Create custom middleware

Frontend Extensions: - Components: Create custom React components - Hooks: Develop custom React hooks - Pages: Add new pages and routes - Themes: Create custom themes and styling

Customization Levels

Configuration Customization: - Environment Variables: Customize via environment settings - Feature Flags: Enable/disable features via configuration - UI Themes: Customize appearance and branding - Workflow Settings: Adjust workflow parameters

Code Customization: - Plugin Architecture: Develop plugins for extensibility - API Extensions: Extend API functionality - Custom Services: Implement custom business logic - Database Extensions: Add custom database schemas

🛠️ Backend Customization

API Extensions

Custom Endpoints:

# backend/api/custom_endpoints.py
from fastapi import APIRouter

router = APIRouter(prefix="/api/custom", tags=["custom"])

@router.get("/my-feature")
async def my_custom_feature():
    """Custom feature endpoint."""
    return {"message": "Custom feature response"}

Service Extensions:

# backend/services/custom_service.py
class CustomService:
    async def process_custom_data(self, data: dict) -> dict:
        """Process custom data."""
        # Custom business logic here
        return processed_data

Model Extensions

Custom Models:

# backend/models/custom_models.py
from sqlalchemy import Column, Integer, String, DateTime
from backend.models.base import Base

class CustomData(Base):
    __tablename__ = "custom_data"

    id = Column(Integer, primary_key=True)
    name = Column(String(255), nullable=False)
    created_at = Column(DateTime, default=datetime.utcnow)

Pydantic Models:

# backend/models/custom_requests.py
from pydantic import BaseModel

class CustomRequest(BaseModel):
    field1: str
    field2: int
    field3: Optional[str] = None

class CustomResponse(BaseModel):
    result: str
    data: dict

Middleware Customization

Custom Middleware:

# backend/middleware/custom_middleware.py
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware

class CustomMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        # Custom middleware logic
        response = await call_next(request)
        return response

🎯 Frontend Customization

Component Development

Custom Components:

// frontend/src/components/Custom/CustomComponent.tsx
import React from 'react';

interface CustomComponentProps {
  title: string;
  data: any[];
  onAction: (item: any) => void;
}

export const CustomComponent: React.FC<CustomComponentProps> = ({
  title,
  data,
  onAction
}) => {
  return (
    <div className="custom-component">
      <h2>{title}</h2>
      {data.map((item, index) => (
        <div key={index} onClick={() => onAction(item)}>
          {item.name}
        </div>
      ))}
    </div>
  );
};

Custom Hooks:

// frontend/src/hooks/useCustomData.ts
import { useState, useEffect } from 'react';

export const useCustomData = (endpoint: string) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch(`/api/custom/${endpoint}`);
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    };

    fetchData();
  }, [endpoint]);

  return { data, loading, error };
};

Theme Customization

Custom Themes:

/* frontend/src/themes/custom-theme.css */
:root {
  --primary-color: #your-brand-color;
  --secondary-color: #your-secondary-color;
  --accent-color: #your-accent-color;
  --background-color: #your-background-color;
  --text-color: #your-text-color;
}

.custom-theme {
  --primary-color: var(--primary-color);
  --secondary-color: var(--secondary-color);
  /* Additional custom variables */
}

Styled Components:

// frontend/src/components/Custom/StyledComponents.tsx
import styled from 'styled-components';

export const CustomContainer = styled.div`
  background-color: var(--primary-color);
  padding: 2rem;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
`;

export const CustomButton = styled.button`
  background-color: var(--accent-color);
  color: white;
  border: none;
  padding: 0.5rem 1rem;
  border-radius: 4px;
  cursor: pointer;

  &:hover {
    opacity: 0.8;
  }
`;

📊 Integration Development

External API Integration

API Client:

# backend/services/external_api_client.py
import httpx
from typing import Dict, Any

class ExternalAPIClient:
    def __init__(self, api_key: str, base_url: str):
        self.api_key = api_key
        self.base_url = base_url
        self.client = httpx.AsyncClient()

    async def get_data(self, endpoint: str) -> Dict[str, Any]:
        """Get data from external API."""
        headers = {"Authorization": f"Bearer {self.api_key}"}
        response = await self.client.get(
            f"{self.base_url}/{endpoint}",
            headers=headers
        )
        return response.json()

Integration Service:

# backend/services/integration_service.py
class IntegrationService:
    def __init__(self):
        self.external_client = ExternalAPIClient(
            api_key=settings.EXTERNAL_API_KEY,
            base_url=settings.EXTERNAL_API_URL
        )

    async def sync_data(self) -> Dict[str, Any]:
        """Sync data with external service."""
        external_data = await self.external_client.get_data("sync")
        # Process and store data
        return {"status": "synced", "data": external_data}

Database Integration

Custom Database Operations:

# backend/services/custom_db_service.py
from sqlalchemy.orm import Session
from backend.models.custom_models import CustomData

class CustomDBService:
    def __init__(self, db: Session):
        self.db = db

    async def create_custom_data(self, data: dict) -> CustomData:
        """Create custom data record."""
        custom_data = CustomData(**data)
        self.db.add(custom_data)
        self.db.commit()
        return custom_data

    async def get_custom_data(self, data_id: int) -> CustomData:
        """Get custom data by ID."""
        return self.db.query(CustomData).filter(
            CustomData.id == data_id
        ).first()

🎯 Advanced Customization

Plugin Architecture

Plugin Interface:

# backend/plugins/base_plugin.py
from abc import ABC, abstractmethod
from typing import Dict, Any

class BasePlugin(ABC):
    @abstractmethod
    def initialize(self, config: Dict[str, Any]) -> None:
        """Initialize plugin with configuration."""
        pass

    @abstractmethod
    def execute(self, data: Dict[str, Any]) -> Dict[str, Any]:
        """Execute plugin logic."""
        pass

    @abstractmethod
    def cleanup(self) -> None:
        """Cleanup plugin resources."""
        pass

Plugin Implementation:

# backend/plugins/custom_plugin.py
from backend.plugins.base_plugin import BasePlugin

class CustomPlugin(BasePlugin):
    def initialize(self, config: Dict[str, Any]) -> None:
        """Initialize custom plugin."""
        self.config = config
        # Initialize plugin resources

    def execute(self, data: Dict[str, Any]) -> Dict[str, Any]:
        """Execute custom plugin logic."""
        # Process data according to plugin logic
        return {"processed": data, "plugin": "custom"}

    def cleanup(self) -> None:
        """Cleanup plugin resources."""
        # Clean up resources

Custom Workflows

Workflow Engine:

# backend/services/workflow_engine.py
from typing import List, Dict, Any

class WorkflowStep:
    def __init__(self, name: str, function: callable):
        self.name = name
        self.function = function

class WorkflowEngine:
    def __init__(self):
        self.steps: List[WorkflowStep] = []

    def add_step(self, step: WorkflowStep):
        """Add workflow step."""
        self.steps.append(step)

    async def execute_workflow(self, data: Dict[str, Any]) -> Dict[str, Any]:
        """Execute workflow with data."""
        result = data
        for step in self.steps:
            result = await step.function(result)
        return result

🛠️ Configuration Management

Environment Configuration

Custom Environment Variables:

# backend/config/custom_config.py
from pydantic import BaseSettings

class CustomSettings(BaseSettings):
    custom_api_key: str
    custom_api_url: str
    custom_feature_enabled: bool = False
    custom_timeout: int = 30

    class Config:
        env_file = ".env"

Feature Flags:

# backend/services/feature_flags.py
class FeatureFlags:
    def __init__(self):
        self.flags = {
            "custom_feature": os.getenv("CUSTOM_FEATURE_ENABLED", "false").lower() == "true",
            "advanced_analytics": os.getenv("ADVANCED_ANALYTICS_ENABLED", "false").lower() == "true",
        }

    def is_enabled(self, feature: str) -> bool:
        """Check if feature is enabled."""
        return self.flags.get(feature, False)

Frontend Configuration

Runtime Configuration:

// frontend/src/config/runtime.ts
interface RuntimeConfig {
  customApiUrl: string;
  customFeatureEnabled: boolean;
  customTimeout: number;
}

export const getRuntimeConfig = (): RuntimeConfig => ({
  customApiUrl: process.env.REACT_APP_CUSTOM_API_URL || '/api/custom',
  customFeatureEnabled: process.env.REACT_APP_CUSTOM_FEATURE_ENABLED === 'true',
  customTimeout: parseInt(process.env.REACT_APP_CUSTOM_TIMEOUT || '30000'),
});

📈 Testing Customizations

Backend Testing

Custom Test Cases:

# tests/test_custom_features.py
import pytest
from fastapi.testclient import TestClient

def test_custom_endpoint(client: TestClient):
    """Test custom endpoint."""
    response = client.get("/api/custom/my-feature")
    assert response.status_code == 200
    assert response.json()["message"] == "Custom feature response"

def test_custom_service():
    """Test custom service."""
    service = CustomService()
    result = await service.process_custom_data({"test": "data"})
    assert result is not None

Frontend Testing

Custom Component Testing:

// src/components/Custom/__tests__/CustomComponent.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import { CustomComponent } from '../CustomComponent';

test('renders custom component', () => {
  const mockData = [{ name: 'Test Item 1' }, { name: 'Test Item 2' }];
  const mockAction = jest.fn();

  render(
    <CustomComponent 
      title="Test Title" 
      data={mockData} 
      onAction={mockAction} 
    />
  );

  expect(screen.getByText('Test Title')).toBeInTheDocument();
  expect(screen.getByText('Test Item 1')).toBeInTheDocument();
});

🎯 Deployment Customizations

Custom Docker Configuration

Custom Dockerfile:

# Dockerfile.custom
FROM python:3.9-slim

# Install custom dependencies
RUN pip install custom-package

# Copy custom configuration
COPY custom_config.py /app/
COPY custom_plugins/ /app/plugins/

# Set custom environment
ENV CUSTOM_FEATURE_ENABLED=true

Custom Docker Compose:

# docker-compose.custom.yml
services:
  alwrity-custom:
    build:
      context: .
      dockerfile: Dockerfile.custom
    environment:
      - CUSTOM_API_KEY=${CUSTOM_API_KEY}
      - CUSTOM_FEATURE_ENABLED=true
    volumes:
      - ./custom_plugins:/app/plugins

🎯 Best Practices

Customization Best Practices

Code Organization: 1. Separation of Concerns: Keep custom code separate from core code 2. Modular Design: Design customizations as modular components 3. Documentation: Document all customizations thoroughly 4. Testing: Test all customizations thoroughly 5. Version Control: Use proper version control for custom code

Performance Considerations: - Optimization: Optimize custom code for performance - Caching: Implement caching for custom features - Resource Management: Manage resources efficiently - Monitoring: Monitor custom feature performance

🎯 Next Steps

Immediate Actions (This Week)

  1. Requirements Analysis: Define customization requirements
  2. Architecture Planning: Plan customization architecture
  3. Development Setup: Set up development environment for customization
  4. Proof of Concept: Create proof of concept for key customizations

Short-Term Planning (This Month)

  1. Core Customizations: Implement core customization features
  2. Testing: Develop comprehensive tests for customizations
  3. Documentation: Document customization process and usage
  4. Integration: Integrate customizations with existing system

Long-Term Strategy (Next Quarter)

  1. Advanced Features: Implement advanced customization features
  2. Plugin System: Develop comprehensive plugin system
  3. Community: Share customizations with community
  4. Maintenance: Establish maintenance and update procedures

Ready to customize ALwrity? Start with Codebase Exploration to understand the architecture before implementing your customizations!