Files
school_compare/backend/config.py
Tudor 4b02ab3d8a
All checks were successful
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 1m1s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 1m7s
Build and Push Docker Images / Build Integrator (push) Successful in 55s
Build and Push Docker Images / Build Kestra Init (push) Successful in 31s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 1m25s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
feat: wire Typesense search into backend, fix sync performance data bug
sync_typesense.py:
- Fix query string replacement: was matching 'ST_X(l.geom) as lng' but
  QUERY_BASE uses 'l.longitude as lng' — KS2/KS4 lateral joins were
  silently dropped on every sync run

backend:
- Add typesense_url/typesense_api_key settings to config.py
- Add search_schools_typesense() to data_loader.py — queries Typesense
  'schools' alias, returns URNs in relevance order with typo tolerance;
  falls back to empty list if Typesense is unavailable
- /api/schools: replace pandas str.contains with Typesense search;
  results are filtered from the DataFrame and returned in relevance order;
  graceful fallback to substring match if Typesense is down

requirements.txt: add typesense==0.21.0, numpy==1.26.4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 13:23:32 +00:00

57 lines
1.5 KiB
Python

"""
Application configuration using pydantic-settings.
Loads from environment variables and .env file.
"""
import secrets
from pathlib import Path
from typing import List, Optional
from pydantic_settings import BaseSettings
from pydantic import Field
class Settings(BaseSettings):
"""Application settings loaded from environment."""
# Paths
data_dir: Path = Path(__file__).parent.parent / "data"
frontend_dir: Path = Path(__file__).parent.parent / "frontend"
# Server
host: str = "0.0.0.0"
port: int = 80
debug: bool = False # Set to False in production
# Database
database_url: str = "postgresql://schoolcompare:schoolcompare@localhost:5432/schoolcompare"
# CORS - Production should only allow the actual domain
allowed_origins: List[str] = ["https://schoolcompare.co.uk"]
# API
default_page_size: int = 50
max_page_size: int = 100
# Security
admin_api_key: str = Field(default_factory=lambda: secrets.token_urlsafe(32))
rate_limit_per_minute: int = 60 # Requests per minute per IP
rate_limit_burst: int = 10 # Allow burst of requests
max_request_size: int = 1024 * 1024 # 1MB max request size
# Typesense
typesense_url: str = "http://localhost:8108"
typesense_api_key: str = ""
# Analytics
ga_measurement_id: Optional[str] = "G-J0PCVT14NY" # Google Analytics 4 Measurement ID
class Config:
env_file = ".env"
env_file_encoding = "utf-8"
extra = "ignore"
# Singleton instance
settings = Settings()