How The Core Platform Features Were Implemented

This page documents the major implementation features in the application codebase and explains how each feature was built, what frameworks and services were used, and how the components integrate at runtime. Each feature is described as a separate subsection for clarity.

Implementation Coverage

  • Agent pipeline, data connectors, language verification, and persistence.
  • Admin platform workflows for create, run, manage, and delete report data.
  • Analyst and operations feature additions including map overlays, chat, and delta tracking.
7 core feature groups
4 external ingestion connectors
3 runtime services
1 unified implementation narrative

Page Map

Feature 1: Agent Pipeline

This section covers the retrieval layer, the LangGraph orchestration flow, the verification loop, and the JSON-oriented persistence path that turns raw evidence into stored reports.

1a. Data Ingestion Agent

The ingestion layer runs one coordinated retrieval pipeline that writes dated JSON snapshots for each country and source. Those snapshots follow the pattern country_source_dataset_YYYYMMDD.json, so later report-generation runs can use a stable evidence date instead of relying on live external APIs at runtime.

GDELT event and media monitoring

GDELT is a global event and news-monitoring dataset. The agent retrieves events and gkg streams for the selected country, then uses them as narrative evidence for topic identification, section analysis, and grounded report writing.

HDX HAPI structured humanitarian indicators

HDX HAPI provides the structured datasets behind the quantitative side of the report. The pipeline fetches idps, refugees, returnees, humanitarian_needs, operational_presence, funding, conflict_events, national_risk, food_security, food_prices, poverty_rate, rainfall, and baseline_population for indicators, key figures, tables, and factual grounding.

ReliefWeb reports and disaster feeds

ReliefWeb is the project's operational document source. The ingestion run stores reports and disasters records, which are later summarised into report sections and bibliography entries so narrative claims can be tied back to humanitarian publications.

Copernicus rapid mapping activations and AOIs

Copernicus EMS Rapid Mapping publishes emergency geospatial products derived from satellite imagery. The system stores the selected activation and cached AOI layers, then reuses them in the map view so analysts can see crisis footprints and mapped areas inside the UI.

The result is a dated evidence pack: structured humanitarian records from HDX, operational reports from ReliefWeb, narrative event streams from GDELT, and geospatial activation layers from Copernicus, all serialised as reusable JSON snapshots for orchestration and admin status checks.

1b. Agent Pipeline Nodes and Language Verification

The runtime graph is defined as a LangGraph workflow using a typed WorkflowState and explicit nodes: load_data, extract_data, identify_topics, generate_indicators, analyze_sections, write_report, score_confidence, analyze_gaps, generate_bibliography, generate_dual_view, verify_language, and generate_crisis_overview_description.

The LLM-backed nodes run on Azure-hosted gpt-4o through LangChain's AzureChatOpenAI. That deployment was suitable here because the same model can alternate between strict JSON extraction, topic identification, indicator generation, and longer section synthesis without switching models mid-pipeline. The orchestrator pairs it with JSON and string parsers, retry logic, and bounded temperature settings so each node can stay predictable for its task.

LangGraph Node Registration

Core node registration inside create_workflow().

def create_workflow() -> StateGraph:
    """Create LangGraph workflow for agent orchestration.
    
    Returns:
        Configured StateGraph workflow
    """
    # Create workflow
    workflow = StateGraph(WorkflowState)
    
    # Add nodes
    workflow.add_node("load_data", load_data_node)
    workflow.add_node("extract_data", data_extraction_node)
    workflow.add_node("identify_topics", topic_identification_node)
    workflow.add_node("generate_indicators", smart_indicator_node)
    workflow.add_node("analyze_sections", section_analysis_nodes)
    workflow.add_node("write_report", report_writing_node)
    workflow.add_node("score_confidence", confidence_scoring_node)
    workflow.add_node("analyze_gaps", gap_analysis_node)
    workflow.add_node("generate_bibliography", bibliography_node)
    workflow.add_node("generate_dual_view", dual_view_node)
    workflow.add_node("verify_language", language_verification_node)
    workflow.add_node("generate_crisis_overview_description", crisis_overview_description_node)

AzureChatOpenAI Configuration

The orchestration layer uses one Azure-hosted gpt-4o deployment for both structured extraction and narrative synthesis.

return AzureChatOpenAI(
    azure_deployment=settings.azure_openai_deployment_name,
    openai_api_version=settings.azure_openai_api_version,
    azure_endpoint=settings.azure_openai_endpoint,
    api_key=settings.azure_openai_api_key,
    temperature=temperature or settings.temperature,
    max_tokens=settings.max_tokens,
    max_retries=6,
    request_timeout=120,
)

The language verification stage applies structured rating and confidence checks and can trigger rewrite loops before output is accepted. This is important because the system does not stop at first-pass generation; it explicitly re-checks terminology and style against IFRC reporting expectations.

The most implementation-specific part of the pipeline is the section-generation stage: it does not send all raw content to one prompt. Instead, it separates structured humanitarian datasets from article-style sources, converts GDELT and ReliefWeb entries into compact excerpts, chunks content into bounded batches, performs section-level extraction, and then runs a synthesis pass to assemble the final narrative. This staged approach was chosen to keep prompts within model context limits and to make section failures easier to debug.

Chunked Section Analysis

This is the core report-writing behaviour: content is split into batches, analysed section by section, then synthesised into one final narrative for each section.

CHUNK_SIZE = 200
content_chunks = [all_content[i:i + CHUNK_SIZE] for i in range(0, len(all_content), CHUNK_SIZE)]

for section in narrative_sections:
    chunk_analyses = []
    for chunk_idx, chunk in enumerate(content_chunks, 1):
        chunk_response = await call_llm_with_prompt(
            system_prompt="You extract key facts from news articles and humanitarian reports, grounding analysis in structured data.",
            user_prompt=chunk_user_prompt,
            temperature=0.3
        )

        if chunk_response:
            chunk_analyses.append(chunk_response)
            if chunk_idx < len(content_chunks):
                await asyncio.sleep(5)

    if chunk_analyses:
        final_response = await call_llm_with_prompt(
            system_prompt="You are a humanitarian analyst writing comprehensive reports.",
            user_prompt=synthesis_prompt,
            temperature=0.6
        )

    await asyncio.sleep(30)

1c and 1d. Agent Workflow Integration and Database Persistence

The Django API layer reads and writes report runs and metric-report rows that are later exposed through retrieval endpoints for analyst views, operations views, references, /report/whats-new, and admin deletion workflows. Those rows carry the final report payload as JSON/JSONB-style structures such as sections, dual views, bibliography, and metadata, which become the persistence backbone used by the main pages, admin tools, and chatbot report-context retrieval.

Persistence is implemented through direct PostgreSQL access rather than only relying on the Django ORM. Ingestion-side writes use pooled psycopg2 connections, while the chatbot service opens its own asyncpg.create_pool(...) for asynchronous report retrieval. This split matters because the system has both synchronous admin/orchestrator workflows and asynchronous chat traffic, but both operate over the same report and crisis records stored in Azure PostgreSQL.

Agent Pipeline Sequence

Ingest

Collect GDELT, HDX, ReliefWeb, and Copernicus data, then freeze it into dated JSON snapshots.

Orchestrate

Run the typed LangGraph pipeline so WorkflowState grows from source data into section outputs.

Verify

Apply IFRC language and confidence checks, with rewrite loops when quality thresholds are not met.

Persist

Save sections, dual views, bibliography, and metadata as final JSON-oriented report artefacts.

Feature 2: AI Chatbot

The chatbot is implemented as a mounted FastAPI service that retrieves stored report JSON before sending bounded questions to Azure OpenAI.

2a. Report loading and prompt assembly

The chatbot API accepts a typed request with report_id, message, and bounded conversation_history. The service first loads stored report content by report identifier, serializes report sections and bibliography into a report-context string, then builds the messages list as: system instructions, current report context, recent conversation turns, and the newest user question.

2b. Runtime model and scope control

This chatbot does not use LangGraph chat memory. Instead, a mounted FastAPI service calls Azure OpenAI gpt-4o through AsyncAzureOpenAI, retrieves report content with asyncpg, and enforces Pydantic request constraints, domain-scoped system prompts, and per-session rate limiting so every answer stays inside IFRC reporting scope.

Chatbot Evidence Snapshots

Feature 3: Mapbox and Copernicus AOI Overlays

Geospatial implementation combines a Mapbox basemap with Copernicus activation lookup, AOI caching, and crisis-aware overlay rendering.

Mapbox is the client-side mapping platform used to render the interactive basemap, camera controls, and visual overlay stack in the analyst UI. In this project it provides the map canvas onto which crisis-country bounds, region overlays, and Copernicus AOI layers are drawn.

Copernicus Emergency Management Service Rapid Mapping publishes emergency geospatial products derived from satellite imagery. The project specifically consumes activation-selection data and cached AOI layers, then uses them to display crisis footprints and mapped areas directly inside the report UI.

In practice, the map flow first resolves the active country configuration for the selected crisis, then looks up a Copernicus activation code, caches the last good result in the browser, and periodically retries until AOI geometry is available for rendering.

Subfeature Implementation Details
3a. Mapbox connection The frontend uses a Mapbox-based map view to render the interactive basemap, camera movement, and active-topic visual state for the currently selected crisis context.
3b. Mapbox region overlays The map layer state is driven by resolved country configuration, so the same component can swap map bounds, zoom, region panels, and topic overlays per crisis-country pair.
3c. Copernicus AOI overlays The overlay workflow performs activation lookup, uses local cache keys and retry timers, and then passes the resolved copernicusActivationCode into the renderer so Copernicus AOI geometry can be drawn directly on the map.

Copernicus Activation Lookup

The map calls the Copernicus activation lookup helper, stores the resolved activation code, and retries periodically if the backend has no result yet.

const fetchActivation = async () => {
    const code = await getCopernicusActivationForCountry(resolvedCountryName);

    if (code) {
        setCopernicusCode((prev) => (prev === code ? prev : code));
        window.localStorage.setItem(cacheKey, code);
        scheduleNext(5 * 60 * 1000);
    } else {
        scheduleNext(20 * 1000);
    }
}

Copernicus Overlay Snapshot

Feature 4: Report Creation, Management, and Deletion in Admin Panel

The admin panel creates crises, triggers ingestion, launches orchestration, and deletes report data through protected backend workflows.

Admin Workflow

Create Crisis

The admin interface posts to /crises/create with typed country and crisis metadata.

Run Retrieval

The panel triggers /crises/ingest and polls /orchestrator/data-status for snapshot readiness.

Generate Reports

Orchestrator runs are launched through /orchestrator/run using selected metric, property, and snapshot date.

Manage and Delete

The delete tab supports /crises/delete and /crises/delete-reports with row-level metric_report_ids selection plus confirmation phrases.

Admin Trigger Behaviour

Long-running ingestion and report generation are started in the background and return immediately to the UI.

threading.Thread(
    target=_run_orchestrator_job,
    args=(crisis, country_name, metric, property_name, data_strategy, data_snapshot_date),
    daemon=True,
).start()

return Response(
    {"detail": "Orchestrator report generation started"},
    status=status.HTTP_202_ACCEPTED,
)

Report Generation Execution

After the admin request is accepted, the backend can optionally refresh ingestion and then run the full agentic pipeline with the selected crisis, metric, property, and snapshot date.

if strategy == "refresh":
    run_ingestion(country_name=country, crisis=crisis_name)

asyncio.run(
    run_orchestrator(
        crisis=crisis_name,
        metric=metric_name,
        property=prop_name,
        country_name=country,
        data_snapshot_date=snapshot_date,
    )
)

Admin Workflow Snapshots

Feature 5: Whats New and Important Info Additions

This feature improves situational awareness by highlighting deltas and surfacing high-priority context in-page.

Whats New implementation

The What's New view builds per-metric property tabs, then calls /report/whats-new with crisis, metric, and property parameters. The response model carries summary, critical_changes, statistical_changes, and key_insights for side-by-side change awareness.

Important Info implementation

Important Info is fed from the same report payload family used by the analyst and operations views, so high-priority updates are promoted without duplicating generation logic.

What's New API Contract

The comparison endpoint validates the request, computes a structured diff, and returns it directly to the UI.

query_serializer = WhatsNewQuerySerializer(data=request.query_params)
query_serializer.is_valid(raise_exception=True)

result = retriever.compute_whats_new()

return Response(_sanitize_mojibake(result), status=status.HTTP_200_OK)

What's New Snapshot

Feature 6: Authentication

Authentication is implemented with Django Auth, session-backed authorization, and CSRF-protected endpoints for secure admin access.

Layer How It Is Implemented
Backend The backend uses Django Auth and exposes /auth/csrf, /auth/login, /auth/logout, and /auth/user, all consumed through cookie-based session auth.
Frontend The frontend refreshes session state and CSRF tokens, while a protected-route layer blocks unauthorized or non-admin access.
Operational controls In deployed configuration, auth tables and session data are stored in Azure PostgreSQL alongside the wider application data, while local development still falls back to SQLite. The admin experience then adds role checks, API preflight state, and mandatory text confirmations before any destructive action executes.

Session Login Behaviour

The login endpoint authenticates credentials, creates the Django session, and returns role information for the frontend guard layer.

user = authenticate(request, username=username, password=password)

if user is not None:
    login(request, user)
    return Response({
        "username": user.username,
        "is_staff": user.is_staff,
        "is_superuser": user.is_superuser,
    })

Authentication Snapshot

Feature 7: System Architecture Additions (Azure and Overall Workflow)

This section consolidates the final deployed topology evidenced in main-branch service wiring and the technical handover architecture narrative.

Runtime Delivery Flow

Client Layer

React pages and components drive analyst, operations, map, and admin workflows from one single-page application.

Delivery Layer

Django provides report, crisis, orchestrator, auth, and map APIs under one gateway.

Processing Layer

The LangGraph node sequence runs report generation, while ingestion and orchestration are invoked by controlled backend endpoints.

Data and Model Layer

The chatbot and orchestrator services use Azure PostgreSQL for persistence and Azure OpenAI deployments for generation and Q&A.

Design Decision Implementation Outcome
Single web runtime for dashboard plus chatbot The ASGI entry point mounts chatbot paths under CHATBOT_MOUNT_PATH and forwards all other paths to Django, with fallback handling if chatbot startup fails.
Separation of concerns without fragmentation Frontend, Django API, orchestrator, and ingestion remain modular codebases but are integrated through explicit endpoints and shared crisis/report identifiers.
Handover-aligned deployment model The technical handover documents this layered architecture and source responsibilities, matching the implemented repository split and Azure-backed runtime services.