Skip to content

Latest commit

 

History

History
1392 lines (1012 loc) · 34.8 KB

File metadata and controls

1392 lines (1012 loc) · 34.8 KB

Wingfix Development Guide

Purpose: This guide covers local development setup, workflows, testing, and code style guidelines for contributing to Wingfix.

Last Updated: March 2026


Quick Start (TL;DR)

For experienced developers who want to get started immediately:

# 1. Clone and setup backend
git clone https://github.com/wingfix/wingfix.git && cd wingfix
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env

# 2. Setup frontend (includes rehype-raw for HTML-in-Markdown rendering)
cd frontend && npm install && cd ..

# 3. Drop your manuals and start everything
cp /path/to/your-manual.pdf data/incoming/
./wingfix-start

# 4. Web UI opens at http://localhost:5173 (dev) or http://localhost (production)
# Use the chat interface with streaming responses and visual citations
# Or run ./wingfix-start --cli for terminal-based interaction
# Type 'exit' or Ctrl+C to stop all services

Table of Contents

  1. Prerequisites
  2. Local Development Setup
  3. Quick Start with wingfix-start
  4. Docker Compose Infrastructure
  5. Running the Application
  6. Running Tests
  7. UI & CLI Testing
  8. Database Migrations
  9. Code Style Guidelines
  10. Development Workflow
  11. Common Tasks
  12. Troubleshooting

Prerequisites

Required Software

Software Version Purpose
Python 3.11+ Primary development language
Node.js 20+ Frontend development (React PWA)
npm or pnpm 10+ / 9+ Package management for frontend
Docker 24.0+ Container runtime for infrastructure services
Docker Compose 2.20+ Multi-container orchestration
Git 2.40+ Version control
ffmpeg 6.0+ Audio format conversion (STT pipeline)

Optional (for GPU inference)

Software Version Purpose
NVIDIA Driver 535+ GPU support
CUDA 12.1+ GPU acceleration
NVIDIA Container Toolkit Latest Docker GPU support

Hardware Requirements

Minimum (CPU-only development):

  • 16GB RAM
  • 50GB disk space
  • 4 CPU cores

Recommended (full system with GPU):

  • 192GB RAM (for in-memory knowledge graph)
  • Dual NVIDIA RTX A6000 (96GB VRAM total)
  • Intel i9-14900K or equivalent
  • NVMe SSD

Local Development Setup

1. Clone the Repository

git clone https://github.com/wingfix/wingfix.git
cd wingfix

2. Create a Virtual Environment

# Create virtual environment
python -m venv .venv

# Activate (Linux/macOS)
source .venv/bin/activate

# Activate (Windows)
.venv\Scripts\activate

3. Install Dependencies

# Development installation (recommended)
pip install -e ".[dev]"

# Or use pinned versions for reproducibility
pip install -r requirements-dev.txt

# IMPORTANT: optimum[onnxruntime] is required for ONNX embedding backend
# Without it, embedding server silently falls back to PyTorch (130-226s load vs ~35s)
pip install 'optimum[onnxruntime]'

4. Set Up Environment Variables

# Copy example environment file
cp .env.example .env

# Edit with your local settings
nano .env  # or your preferred editor

Key environment variables:

# Application
WINGFIX_ENVIRONMENT=development
WINGFIX_DEBUG=true

# Database connections (defaults work with Docker Compose)
WINGFIX_DATABASE__POSTGRES_HOST=localhost
WINGFIX_DATABASE__POSTGRES_PORT=5432
WINGFIX_DATABASE__POSTGRES_PASSWORD=wingfix_dev_password

# Qdrant vector database
WINGFIX_DATABASE__QDRANT_HOST=localhost
WINGFIX_DATABASE__QDRANT_HTTP_PORT=6333

# MinIO object storage
WINGFIX_DATABASE__MINIO_HOST=localhost
WINGFIX_DATABASE__MINIO_PORT=9000
WINGFIX_DATABASE__MINIO_SECRET_KEY=wingfix_dev_password

# Redis cache
WINGFIX_DATABASE__REDIS_HOST=localhost
WINGFIX_DATABASE__REDIS_PORT=6379

# LLM configuration (optional for development)
WINGFIX_MODEL__LLM_BASE_URL=http://localhost:11435/v1

5. Set Up Pre-commit Hooks

# Install pre-commit hooks
pre-commit install

# Run on all files (first-time setup)
pre-commit run --all-files

5b. Install Frontend Dependencies

cd frontend
npm install    # Includes rehype-raw for HTML-in-Markdown rendering
cd ..

6. Create Required Directories

# Creates data/, logs/, and cache directories
python -c "from wingfix.config import ensure_directories; ensure_directories()"

7. Validate Configuration

The startup configuration validator runs automatically during ./wingfix-start, but you can run it manually:

# Validate before launching
python -m wingfix.cli.config_validator

This checks:

  • .env file existence (warns if missing, uses defaults)
  • Required environment variables
  • Port availability (5432, 6333, 9000, 6379)
  • Data directory write permissions
  • Docker daemon availability
  • Ollama installation (warns if missing)

Quick Start with wingfix-start

The easiest way to run Wingfix is using the unified start script that handles all setup automatically.

One-Command Startup

# Start everything with a single command (React dev server is default)
./wingfix-start

This script will:

  1. Validate configuration (ConfigValidator — checks env, ports, directories)
  2. Activate the virtual environment (detects .venv or conda)
  3. Start Docker infrastructure (PostgreSQL, Qdrant, MinIO, Redis)
  4. Run database migrations (MigrationRunner — Alembic upgrade head)
  5. Initialize Qdrant collections (QdrantInitializer — idempotent)
  6. Start Ollama LLM server (with Gemma 4 31B Instruct)
  7. Start WingFix API on port 8082
  8. Start React dev server on port 5173 (Vite HMR)
  9. Ingest documents from data/incoming/
  10. Open browser to http://localhost:5173

Startup Options

./wingfix-start                    # Full startup + React dev server (default)
./wingfix-start --cli              # Use interactive CLI instead of Web UI
./wingfix-start --no-ingest        # Skip document ingestion
./wingfix-start --no-browser       # Don't auto-open browser
./wingfix-start --skip-migrations  # Skip Alembic migrations (for dev)
./wingfix-start --help             # Show all options

Web UI Features

Once the React PWA is running at http://localhost:5173 (dev mode):

Feature Description
Chat Interface Type questions in the chat input at the bottom
Streaming Responses Watch answers appear token-by-token
Citation Viewer Click [1], [2] links to see PDF source in split-screen
Session History Left sidebar shows previous chats (click to restore)
File Upload Drag PDFs into the chat area for ingestion
Theme Toggle Switch between light/dark/system mode in header
Settings Panel Gear icon or Ctrl+, — configure effectivity, voice, shortcuts
Effectivity Context Set tail number, date, station, fleet (persisted across sessions)
Stock Panel Inline inventory availability for part numbers in responses
Safety Blocks Color-coded WARNING / CAUTION / NOTE indicators in responses
Voice Mode Push-to-Talk microphone input + auto read-aloud TTS responses
Print View Print button to produce clean work-card output
PWA Install Install-to-home-screen prompt (tablets / desktops)
Offline Mode Banner when offline; cached manuals remain accessible
Keyboard Shortcuts Ctrl+N, Ctrl+/, Ctrl+K, Escape, Ctrl+M, Ctrl+.

Keyboard Shortcuts Reference

Shortcut Action
Ctrl+N New chat session
Ctrl+/ Focus chat input
Ctrl+K Focus session search in sidebar
Ctrl+, Open settings panel
Ctrl+M Toggle voice mode on/off
Ctrl+. Stop current TTS playback
Escape Close PDF viewer panel

Interactive CLI Commands (Alternative)

When using ./wingfix-start --cli, you get a terminal interface:

[wingfix]> What is the torque value for IDG mounting bolts?
# (Streaming response with citations)

[wingfix]> status          # Check service health
[wingfix]> ingest file.pdf # Manually ingest a document
[wingfix]> help            # Show available commands
[wingfix]> exit            # Graceful shutdown

One-Command Shutdown

./wingfix-stop                     # Graceful stop (preserve data)
./wingfix-stop --force             # Force kill all processes
./wingfix-stop --clean             # Stop and remove all data (DANGER!)
./wingfix-stop --api-only          # Stop only API (keep infra running)

Docker Compose Infrastructure

Wingfix uses Docker Compose to manage infrastructure services locally.

Services Overview

Service Port Purpose
PostgreSQL 16 5432 Metadata store (documents, parts, policies, sessions)
Qdrant 6333 (HTTP), 6334 (gRPC) Vector database for embeddings
MinIO 9000 (API), 9001 (Console) S3-compatible object storage
Redis 6379 Caching and job queue

Starting Infrastructure

# Start all services (recommended method)
./scripts/start-infra.sh

# Or use Docker Compose directly
docker compose up -d

# Start with log following
./scripts/start-infra.sh --logs

# Rebuild containers before starting
./scripts/start-infra.sh --build

Checking Service Health

# Run health check script
./scripts/docker-health-check.sh

# Or check status manually
docker compose ps

Expected output:

==========================================
Wingfix Docker Infrastructure Health Check
==========================================

Checking services...
-------------------------------------------
PostgreSQL:         ✓ Healthy
Qdrant:             ✓ Healthy
MinIO:              ✓ Healthy
Redis:              ✓ Healthy
-------------------------------------------

All services are healthy!

Viewing Logs

# All services
docker compose logs -f

# Specific service
docker compose logs -f postgres
docker compose logs -f qdrant
docker compose logs -f minio
docker compose logs -f redis

Stopping Infrastructure

# Stop services (preserve data)
./scripts/stop-infra.sh

# Stop and remove volumes (DATA LOSS!)
./scripts/stop-infra.sh --clean

# Or use Docker Compose directly
docker compose down        # Preserve data
docker compose down -v     # Remove volumes

Accessing Service UIs


Running the Application

Recommended: Using wingfix-start

The recommended way to run Wingfix is using the unified start script:

./wingfix-start

This handles all service orchestration and provides an interactive CLI.

Manual: API Server Only

If you need to run components individually:

# Development mode with auto-reload
uvicorn wingfix.api.main:app --reload --port 8082

# Or using the entry point
wingfix

# Production mode
uvicorn wingfix.api.main:app --host 0.0.0.0 --port 8082 --workers 4

API will be available at:

Manual: React PWA Frontend Only

To run only the React frontend (requires API to be running):

# Development mode with hot reload (Vite HMR)
cd frontend
npm run dev

# Build for production
npm run build

# Preview production build
npm run preview

# Type-check without building
npm run type-check

# Lint
npm run lint

Frontend will be available at:

React Development Tips:

  • Changes to frontend/src/ auto-reload via Vite HMR
  • Use React DevTools browser extension for component inspection
  • Use TanStack Query DevTools for API cache debugging
  • Test SSE consumption with browser dev tools Network tab
  • Theme changes apply immediately via Tailwind dark: classes
  • Effectivity context persists to localStorage — reset via Settings panel

Configuration Verification

# Print configuration summary
python -c "from wingfix.config import print_config_summary; print_config_summary()"

Qdrant Collection Management

# Check collection status
python -m wingfix.cli.qdrant_init status

# Initialize collections (idempotent — safe to run multiple times)
python -m wingfix.cli.qdrant_init init

# Check only (verify, no changes)
python -m wingfix.cli.qdrant_init init --check-only

# Recreate collections (DANGER — deletes all vectors!)
python -m wingfix.cli.qdrant_init init --recreate

Ollama Server (Optional for Manual Setup)

If not using ./wingfix-start, start the Ollama server manually:

# Using the provided script (requires GPU)
./scripts/start_ollama.sh

# Check status
./scripts/start_ollama.sh status

# Stop Ollama
./scripts/start_ollama.sh stop

Note: ./wingfix-start automatically manages Ollama startup and shutdown.


Running Tests

Test Structure

src/tests/
├── conftest.py              # Shared fixtures
├── test_*.py                # Unit tests (~80+ test files)
│   ├── test_auth_middleware.py      # JWT auth tests
│   ├── test_rbac.py                 # Role-based access control tests
│   ├── test_rate_limiter_redis.py   # Redis-backed rate limiting tests
│   ├── test_connection_limits.py    # SSE connection limiter tests
│   ├── test_security_headers.py     # Security headers middleware tests
│   ├── test_prompt_injection_guardrail.py  # Prompt injection detection tests
│   ├── test_subprocess_hardening.py # Subprocess safe execution tests
│   ├── test_temp_manager.py         # Temp file management tests
│   ├── test_pdf_hardening.py        # PDF validator (zip-bomb, malformed) tests
│   ├── test_image_sanitization.py   # Image validator tests
│   ├── test_xxe_prevention.py       # XML XXE prevention tests
│   ├── test_graph_cache_security.py # HMAC graph cache integrity tests
│   ├── test_keyboard_accessibility.py  # Keyboard shortcut and ARIA accessibility tests
│   ├── test_production_config.py    # Production config safety tests
│   └── ... (domain tests: parsers, retrievers, workflow, API endpoints, etc.)
├── integration/             # Integration tests
│   ├── conftest.py
│   ├── test_agent_workflow.py
│   ├── test_health_checks.py
│   ├── test_ingestion_pipeline.py
│   ├── test_knowledge_link.py
│   ├── test_retrieval_pipeline.py
│   └── test_startup_shutdown.py
├── e2e/                     # Playwright browser end-to-end tests
│   ├── conftest.py
│   ├── test_chat_e2e.py
│   ├── test_citations_e2e.py
│   ├── test_upload_e2e.py
│   ├── test_voice_e2e.py        # Voice / audio E2E (Task 14.x)
│   ├── test_voice_ui_e2e.py     # Voice UI component tests
│   ├── test_theme_e2e.py
│   ├── test_responsive_e2e.py
│   └── visual/                  # Visual regression baselines
│       └── test_visual_regression.py
├── cli/                     # Pexpect interactive CLI tests
│   ├── conftest.py
│   ├── test_cli_interactive.py
│   └── test_cli_ingest.py
├── eval/                    # Evaluation tests
│   ├── eval_dataset.json
│   ├── synthetic_eval_dataset.json
│   ├── run_eval.py
│   ├── test_eval.py
│   ├── models.py
│   └── synthetic_generator.py
└── benchmarks/              # Performance benchmarks
    ├── bench_embedding.py
    ├── bench_ingestion.py
    └── bench_retrieval.py

Running Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=wingfix --cov-report=html

# Run specific test file
pytest src/tests/test_pn_extractor.py

# Run specific test function
pytest src/tests/test_pn_extractor.py::test_boeing_pn_format

# Run tests with verbose output
pytest -v

# Run tests matching a pattern
pytest -k "pn_extract"

Security Tests

# Run all security-related tests
pytest -k "security or injection or rbac or rate_limiter or hardening"

# Prompt injection guardrail tests
pytest src/tests/test_prompt_injection_guardrail.py -v

# JWT auth and RBAC tests
pytest src/tests/test_auth_middleware.py src/tests/test_rbac.py -v

# Redis-backed rate limiter tests
pytest src/tests/test_rate_limiter_redis.py -v

# SSE connection limiter tests
pytest src/tests/test_connection_limits.py -v

# Security headers tests
pytest src/tests/test_security_headers.py -v

# Subprocess hardening tests
pytest src/tests/test_subprocess_hardening.py -v

# Temp file management tests
pytest src/tests/test_temp_manager.py -v

# PDF/image validation tests
pytest src/tests/test_pdf_hardening.py src/tests/test_image_sanitization.py -v

# XML XXE prevention tests
pytest src/tests/test_xxe_prevention.py -v

# Graph cache integrity tests
pytest src/tests/test_graph_cache_security.py -v

# Keyboard accessibility tests
pytest src/tests/test_keyboard_accessibility.py -v

# Production config safety tests
pytest src/tests/test_production_config.py -v

Test Markers

# Skip slow tests
pytest -m "not slow"

# Skip integration tests
pytest -m "not integration"

# Run only integration tests
pytest -m integration

# Run only GPU-required tests
pytest -m gpu

# Run benchmarks
pytest -m benchmark

Coverage Report

# Generate HTML coverage report
pytest --cov=wingfix --cov-report=html

# View report
xdg-open htmlcov/index.html  # Linux

Integration Tests

Integration tests require Docker services to be running:

# Start infrastructure first
./scripts/start-infra.sh

# Run integration tests
pytest -m integration

# Run with specific database
WINGFIX_DATABASE__POSTGRES_DB=wingfix_test pytest -m integration

UI & CLI Testing

Wingfix uses Playwright for browser E2E tests and Pexpect for interactive CLI tests. It also uses Vitest for React unit tests. These tests validate the visual and interactive components of the application.

Setup

# Install E2E testing dependencies
pip install -e ".[e2e]"

# Or manually install
pip install pytest-playwright pexpect

# Install Playwright browsers (one-time setup)
playwright install chromium

# Optionally install all browsers
playwright install  # chromium, firefox, webkit

# Install frontend test dependencies (already included in package.json devDependencies)
cd frontend
npm install

Running E2E Tests (Playwright)

E2E tests require the full Wingfix stack to be running:

# Start Wingfix services (in background)
./wingfix-start --no-browser &

# Wait for services to be healthy
./scripts/wait_for_services.sh 180

# Run all E2E tests
pytest -m e2e tests/e2e/

# Run specific E2E test file
pytest tests/e2e/test_chat_e2e.py -v

# Run voice/audio E2E tests
pytest tests/e2e/test_voice_e2e.py -v
pytest tests/e2e/test_voice_ui_e2e.py -v

# Run with visible browser (headed mode for debugging)
pytest -m e2e --headed

# Run with slow motion for visual debugging
pytest -m e2e --headed --slowmo=500

# Run only visual regression tests
pytest tests/e2e/test_theme_e2e.py tests/e2e/test_responsive_e2e.py

# Generate test code interactively (opens browser)
playwright codegen http://localhost:5173

Headless Mode for CI/CD

E2E tests run in headless mode by default, which is suitable for CI/CD pipelines:

# CI-friendly command (no display required)
pytest -m e2e --browser chromium

# Run with Xvfb on Linux CI without display
xvfb-run pytest -m e2e

# Generate JUnit XML report for CI
pytest -m e2e --junitxml=test-results/e2e.xml

GitHub Actions Example:

- name: Install Playwright Browsers
  run: playwright install chromium --with-deps

- name: Start Wingfix Services
  run: |
    ./wingfix-start --no-browser --no-cli &
    ./scripts/wait_for_services.sh 180

- name: Run E2E Tests
  run: pytest -m e2e --browser chromium

- name: Stop Services
  if: always()
  run: ./wingfix-stop --force

Running CLI Tests (Pexpect)

CLI tests spawn interactive terminal sessions and require TTY support:

# Run all CLI tests
pytest tests/cli/ -v

# Run specific CLI test
pytest tests/cli/test_cli_interactive.py::test_cli_query_with_streaming_response

# Run with extended timeout (for slow systems)
pytest tests/cli/ -v --timeout=180

# Skip CLI tests (useful in environments without TTY)
pytest -m "not cli"

Note: CLI tests require a proper TTY and may not work in all CI environments. Use pytest -m "not cli" to skip them when necessary.

Visual Regression Testing

Playwright supports visual comparison testing for catching unintended UI changes:

# Generate baseline screenshots (first run or after intentional changes)
pytest tests/e2e/test_theme_e2e.py --update-snapshots

# Run visual regression tests (compares against baselines)
pytest tests/e2e/test_theme_e2e.py

# View visual diff report (if tests fail)
open test-results/visual-diff.html

Baseline screenshots are stored in tests/e2e/visual/ and should be committed to version control.

Test Markers

# Run only E2E tests
pytest -m e2e

# Run only CLI tests
pytest -m cli

# Run everything except E2E (faster feedback)
pytest -m "not e2e"

# Run everything except CLI (for CI without TTY)
pytest -m "not cli"

# Run unit and integration tests only (skip all UI tests)
pytest -m "not e2e and not cli"

Debugging Failed Tests

Playwright Debugging:

# Enable Playwright debug mode (opens inspector)
PWDEBUG=1 pytest tests/e2e/test_chat_e2e.py -v -k test_chat_query

# Save screenshots on failure
pytest -m e2e --screenshot=on --output=test-results/

# Save video recordings of test runs
pytest -m e2e --video=retain-on-failure --output=test-results/

# Generate trace files for detailed debugging
pytest -m e2e --tracing=retain-on-failure
playwright show-trace test-results/trace.zip

Pexpect Debugging:

# In test code, enable logging to see CLI output
child.logfile = sys.stdout

# Increase timeout for debugging
child.timeout = 300

Running Unit Tests (Vitest)

Wingfix frontend uses Vitest (integrated into Vite) for React component unit tests:

# Run React unit tests
cd frontend
npm run test              # Run once
npm run test -- --watch   # Watch mode (alias: npm run test:watch)
npm run test -- --coverage  # With coverage

# Run a specific test file
npm run test -- src/__tests__/AudioPlayer.test.tsx
npm run test -- src/__tests__/VoiceInput.test.tsx

Writing New E2E Tests

When adding new E2E tests, follow these patterns:

# tests/e2e/test_example_e2e.py
import pytest
from playwright.sync_api import Page, expect

@pytest.mark.e2e
def test_feature_works(wingfix_page: Page):
    """Test description explaining what's being validated."""
    page = wingfix_page
    
    # Arrange: Set up test state
    # ...
    
    # Act: Perform user actions
    page.locator('[data-testid="chat-input"]').fill("What is the torque value?")
    page.locator('[data-testid="send-button"]').click()
    
    # Assert: Verify expected outcome
    expect(page.locator('[data-testid="assistant-message"]')).to_be_visible()

Best Practices:

  1. Use data-testid attributes for reliable selectors (e.g., data-testid="chat-input", data-testid="assistant-message")
  2. Use Playwright's expect() assertions for auto-waiting
  3. Add @pytest.mark.e2e marker to all E2E tests
  4. Keep tests independent (no shared state between tests)
  5. Use fixtures for common setup/teardown

Database Migrations

Wingfix uses Alembic for database migrations. The MigrationRunner class handles migrations programmatically during startup.

Check Current Version

alembic current

# Or via MigrationRunner
python -m wingfix.cli.migration_runner status

Apply All Migrations

alembic upgrade head

# Or via MigrationRunner (captures output, handles errors gracefully)
python -m wingfix.cli.migration_runner upgrade

Rollback One Migration

alembic downgrade -1

Rollback to Specific Version

alembic downgrade 001_initial

Create New Migration

# Auto-generate from model changes
alembic revision --autogenerate -m "Add new column to parts table"

# Create empty migration
alembic revision -m "Custom migration description"

View Migration History

alembic history

Migration Best Practices

  1. Always review auto-generated migrations before applying
  2. Test migrations on a copy of production data
  3. Include both upgrade and downgrade functions
  4. Use descriptive revision messages
  5. The startup MigrationRunner uses --skip mode by default during development — pass ./wingfix-start without --skip-migrations for a clean run

Code Style Guidelines

Formatting

Wingfix uses Black for code formatting with a line length of 100 characters.

# Format all files
black src/

# Check formatting without changing
black --check src/

# Format specific file
black src/wingfix/config.py

Linting

Wingfix uses Ruff for linting (replaces flake8, isort, pyupgrade).

# Run linter
ruff check src/

# Auto-fix issues
ruff check --fix src/

# Check specific file
ruff check src/wingfix/config.py

Type Checking

Wingfix uses mypy for static type checking.

# Type check entire codebase
mypy src/wingfix/

# Type check specific module
mypy src/wingfix/retrieval/

Running All Checks

# Via pre-commit (recommended)
pre-commit run --all-files

# Manually
black src/
ruff check --fix src/
mypy src/wingfix/

Code Style Summary

Aspect Standard
Line length 100 characters
Quotes Double quotes (")
Imports Sorted by isort (via Ruff)
Type hints Required for all public functions
Docstrings Google style
Naming snake_case for functions/variables, PascalCase for classes

Example Code Style

"""Module docstring describing purpose.

Extended description if needed.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from wingfix.config import get_settings

if TYPE_CHECKING:
    from wingfix.models.llm_client import LLMClient


class PartExtractor:
    """Extract part numbers from aviation documents.

    This class handles extraction of Boeing, NAS, AN, and MS part numbers
    using both regex patterns and ML-based tagging.

    Attributes:
        confidence_threshold: Minimum confidence for extraction (0-1).
        patterns: Compiled regex patterns for PN formats.
    """

    def __init__(self, confidence_threshold: float = 0.8) -> None:
        """Initialize the part extractor.

        Args:
            confidence_threshold: Minimum confidence score to accept
                an extracted part number. Defaults to 0.8.
        """
        self.confidence_threshold = confidence_threshold
        self._compile_patterns()

    def extract(self, text: str) -> list[str]:
        """Extract part numbers from text.

        Args:
            text: Input text to scan for part numbers.

        Returns:
            List of extracted part numbers (normalized format).

        Raises:
            ValueError: If text is empty or None.
        """
        if not text:
            raise ValueError("Text cannot be empty")

        results = []
        # Implementation...
        return results

Development Workflow

Branch Naming

feature/add-mel-parser
bugfix/fix-pn-extraction
refactor/optimize-retrieval
docs/update-api-docs

Commit Messages

Follow Conventional Commits:

feat: add MEL deferral parser
fix: correct PN normalization for NAS format
docs: update API endpoint documentation
refactor: optimize vector search query
test: add integration tests for Knowledge Link
chore: update dependencies

Pull Request Process

  1. Create feature branch from main
  2. Make changes with tests
  3. Ensure all checks pass: pre-commit run --all-files
  4. Run test suite: pytest
  5. Run frontend tests: cd frontend && npm run test
  6. Push and create PR
  7. Address review feedback
  8. Squash and merge

Common Tasks

Adding a New Document Parser

  1. Create parser in src/wingfix/ingestion/parsers/
  2. Add Pydantic models in *_models.py
  3. Register in src/wingfix/ingestion/parsers/__init__.py
  4. Add unit tests in src/tests/test_*_parser.py
  5. Update document type enum if needed

Adding a New API Endpoint

  1. Create route in src/wingfix/api/routes/
  2. Add Pydantic request/response models
  3. Register router in src/wingfix/api/main.py
  4. Add tests in src/tests/test_api.py
  5. OpenAPI docs generate automatically at http://localhost:8082/docs

Adding a New Workflow Node

  1. Create node in src/wingfix/agents/nodes/
  2. Define state updates and routing logic
  3. Register in src/wingfix/agents/workflow.py
  4. Add conditional edges for routing
  5. Update workflow diagram in docs

Adding a New Frontend Component

  1. Create component in frontend/src/components/
  2. Add data-testid attributes for E2E test selectors
  3. Use existing contexts via hooks: useTheme, useAuth, useEffectivity, useSession, useVoiceMode
  4. Follow the existing pattern using Tailwind CSS + dark: variants
  5. Export from component file; import directly (Vite path aliases: @/ maps to src/)
  6. Add Vitest unit tests in frontend/src/__tests__/

Adding a Security Middleware

  1. Create middleware in src/wingfix/api/middleware/
  2. Follow the existing pattern (auth.py, rbac.py, rate_limiter.py)
  3. Register in src/wingfix/api/main.py lifespan or middleware stack
  4. Add tests in src/tests/test_<middleware_name>.py
  5. Update configs/default.yaml if the middleware needs configuration
  6. Document in the Architecture doc's Security Layer section

Regenerating Embeddings

# Clear embedding cache
python -c "from wingfix.storage.object_store import ObjectStore; ObjectStore().clear_bucket('embeddings-cache')"

# Re-run indexing
python -m wingfix.indexing.text_embedder --reindex

Testing Voice/Audio Features

The audio pipeline requires ffmpeg installed on the host. Test it manually:

# Check STT endpoint (requires Whisper model loaded)
curl -X POST http://localhost:8082/api/v1/audio/transcribe \
    -F "audio=@data/test/test-audio.wav" | jq

# Check TTS endpoint (requires Kokoro ONNX models in data/models/kokoro-v1.0/)
curl -X POST http://localhost:8082/api/v1/audio/synthesize \
    -H "Content-Type: application/json" \
    -d '{"text": "Check oil filter torque value before installation.", "voice": "am_michael"}' \
    --output output.wav

# Check audio service health
curl http://localhost:8082/health | jq '.services.audio'

Available TTS voices: am_michael, af_sarah, bf_emma, bm_george

TTS speed range: 0.5x – 2.0x

Managing Sessions

# List all sessions
curl http://localhost:8082/api/v1/sessions | jq

# Get specific session with messages
curl http://localhost:8082/api/v1/sessions/{session_id} | jq

# Search sessions
curl "http://localhost:8082/api/v1/sessions/search?q=IDG+filter" | jq

# Delete session
curl -X DELETE http://localhost:8082/api/v1/sessions/{session_id}

Troubleshooting

Docker Issues

Services won't start:

# Check for port conflicts
lsof -i :5432  # PostgreSQL
lsof -i :6333  # Qdrant
lsof -i :9000  # MinIO
lsof -i :6379  # Redis

# Reset Docker environment
docker compose down -v
docker system prune -f
./scripts/start-infra.sh

Connection refused errors:

# Verify services are healthy
./scripts/docker-health-check.sh

# Check container logs
docker compose logs postgres

Database Issues

Migration errors:

# Reset database (development only!)
docker compose down -v
./scripts/start-infra.sh
alembic upgrade head

Connection pool exhausted:

# Increase pool size in config
WINGFIX_DATABASE__POSTGRES_POOL_SIZE=10
WINGFIX_DATABASE__POSTGRES_MAX_OVERFLOW=20

Import Errors

Module not found:

# Ensure package is installed in editable mode
pip install -e ".[dev]"

# Check Python path
python -c "import wingfix; print(wingfix.__file__)"

GPU/CUDA Issues

CUDA out of memory:

# Clear GPU memory
nvidia-smi --gpu-reset

# Check GPU utilization
nvidia-smi -l 1

# Reduce batch sizes in config
WINGFIX_MODEL__EMBEDDING_BATCH_SIZE=8

Audio / Voice Issues

ffmpeg not found:

# Install on Ubuntu/Debian
sudo apt install ffmpeg

# Verify
ffmpeg -version

STT returns empty transcript:

# Check Whisper model is loaded
curl http://localhost:8082/health | jq '.services.audio.stt'

# Check audio format (must be WebM, WAV, MP3, OGG, FLAC, or M4A)
# Max file size: 25 MB

TTS produces no audio:

# Verify Kokoro models exist
ls data/models/kokoro-v1.0/
# Expected: kokoro-v1.0.onnx  voices-v1.0.bin

# Check TTS health
curl http://localhost:8082/health | jq '.services.audio.tts'

Rate limiting errors (429):

  • STT: 30 transcriptions/minute
  • TTS: 60 syntheses/minute
  • Wait 60 seconds and retry

Qdrant Collection Issues

Collection not found or wrong dimensions:

# Check collection status
python -m wingfix.cli.qdrant_init status

# Reinitialize (safe for existing data)
python -m wingfix.cli.qdrant_init init

# Force recreate (DANGER — destroys all vectors)
python -m wingfix.cli.qdrant_init init --recreate
alembic downgrade base && alembic upgrade head  # also reset metadata

Frontend Issues

PWA install prompt not showing:

  • Requires HTTPS or localhost
  • Browser must not have dismissed the prompt previously — use DevTools > Application > Manifest to reset

Effectivity context not persisting:

# Check localStorage in DevTools (Application > Local Storage > localhost:5173)
# Key: wingfix-effectivity

TanStack Query not caching:

# Open React Query DevTools (gear icon in bottom-right corner during dev)
# Look for stale/refetching queries

Test Failures

Fixture not found:

# Ensure conftest.py is in correct location
# Check test collection
pytest --collect-only

Async test issues:

# Ensure pytest-asyncio is installed
pip install pytest-asyncio

# Check asyncio mode in pyproject.toml
# asyncio_mode = "auto"

Vitest failures:

cd frontend
npm run type-check  # Check for TypeScript errors first
npm run test -- --reporter=verbose

Getting Help

  • Documentation: Check docs/ directory
  • Issues: Open a GitHub issue
  • Code Questions: Review existing code for patterns
  • OpenAPI Docs: http://localhost:8082/docs (when API is running)

Built for Aircraft Maintenance Engineers ✈️