A modern web application for exploring UK postcodes, districts and towns with spatial search capabilities. Built with Cursor and Lovable. Uses React, TypeScript, shadcn/ui, Mapbox GL JS and Tailwind CSS at the frontend. FastAPI and SQLite with Spatialite extension at the backend.
- Spatial Search: Search locations within a specified radius of any point
- Multi-mode Search: Search by postcode, town, or county
- Interactive Map: Visual representation of search results with Mapbox integration
- Geofencing: Display and filter results within a specified radius
- Mock Data Support: Fallback to mock data when backend is unavailable
- Modern UI: Built with React, TypeScript, and shadcn/ui
Type a location string to return a set of related postcode rows. Select a row to throw an adjustable geofence around that postcode:

- UI Components: Built with shadcn/ui and Tailwind CSS
- Map Integration: Uses Mapbox GL JS for interactive mapping
- State Management: React hooks and context for local state
- API Layer: Typed API client with error handling and mock data support
- Routing: React Router for navigation
- Styling: Tailwind CSS with dark mode support
- API Framework: FastAPI with automatic OpenAPI documentation
- Database: SQLite with SpatiaLite extension for spatial queries
- Performance Optimizations:
- LRU caching with configurable size and TTL
- Connection pooling
- Indexed spatial queries
- Parameterized SQL for security
- Security Features:
- CORS protection
- Input validation
- Rate limiting support
- Secure error handling
The application uses SpatiaLite for efficient spatial queries:
-
Spatial Indexing:
- R*Tree spatial index on latitude/longitude columns
- Optimized for range and radius queries
- Supports efficient geofencing operations
-
Distance Calculations:
- Uses geodesic distance calculations
- Supports radius-based searches
- Results sorted by distance from center point
-
Geofencing:
- Dynamic radius adjustment (100m to 50km)
- Visual representation on map
- Real-time filtering of results
-
GET /search/postcode/{postcode}
- Search by full or partial postcode
- Supports spatial parameters
-
GET /search/town/{town}
- Search by town name
- Includes district matching
- Supports spatial parameters
-
GET /search/county/{county}
- Search by county name
- Supports spatial parameters
GET /search/spatial
- Search locations within radius
- Parameters:
center_lat
: Center latitude (-90 to 90)center_lon
: Center longitude (-180 to 180)radius_meters
: Search radius (0 to 50000)limit
: Maximum results (1-5000)
All search endpoints support the following query parameters:
limit
: Maximum number of results to returncenter_lat
: Center latitude for spatial searchcenter_lon
: Center longitude for spatial searchradius_meters
: Search radius in meters
- Node.js & npm
- Python 3.11+
- SQLite with SpatiaLite extension
- UK Postcode Address File (PAF) data
- Install system dependencies:
macOS:
# Install SpatiaLite and its dependencies
$ brew update
$ brew install spatialite-tools
- Create a Python virtual environment and install dependencies:
# Create and activate virtual environment
$ python -m venv venv
$ source venv/bin/activate
# Install Python dependencies
$ cd backend
$ pip install -r requirements.txt
$ pip install pandas matplotlib seaborn python-multipart docopt
- Create the database in /backend/data:
$ python csv_to_sqlite.py -c locations.csv
- Start the backend:
$ python -m uvicorn location_api:app --reload
The API documentation will be available at:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc

- Install dependencies:
$ npm install
- Create a
.env
file with your Mapbox token:
VITE_MAPBOX_TOKEN=your_mapbox_token_here
- Start the development server:
$ npm run dev
The project includes Docker and Terraform configurations for containerized deployment:
$ cd terraform
$ terraform init
$ terraform apply
This will:
- Build and run the backend container
- Build and run the frontend container
- Create a Docker network for communication
- Mount the database volume
- Configure environment variables
- All inputs are validated and sanitized
- SQL injection protection through parameterized queries
- CORS protection with configurable origins
- Rate limiting support
- Secure error handling and logging
- Content Security Policy headers
- XSS protection headers
The application is optimized for performance:
-
Frontend:
- Code splitting and lazy loading
- Optimized asset delivery
- Efficient state management
- Debounced search inputs
-
Backend:
- LRU caching (configurable size and TTL)
- Connection pooling
- Indexed queries
- Optimized spatial calculations
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.