152 lines
4.1 KiB
Markdown

# Postal Code Geocoding Cache
## Overview
The postal code geocoding cache system stores geographic coordinates for Canadian postal codes, enabling faster representative lookups and reducing external API calls. It integrates with the multi-provider geocoding service to provide reliable centroid calculations for postal code-based geographic queries.
**Key Capabilities:**
- **Postal code caching**: Store lat/lng centroids for postal codes
- **Geocoding integration**: Automatic geocoding via multi-provider service
- **Cache hit optimization**: Reduce external API calls
- **Administrative data**: City and province extraction
- **Representative lookup**: Fast postal code → representative mapping
**Use Cases:**
- Campaign postal code lookups
- Geographic representative mapping
- Postal code validation
- Centroid-based spatial queries
## Architecture
```mermaid
graph TD
A[Campaign Service] -->|Lookup Postal Code| B[Postal Code Service]
B -->|Check Cache| C{Cache Hit?}
C -->|Yes| D[Return Cached Centroid]
C -->|No| E[Geocoding Service]
E -->|Geocode| F[Multi-Provider Geocoding]
F -->|Parse Result| G[Extract Centroid]
G -->|Save| H[(PostalCodeCache Model)]
H -->|Return| D
I[Admin] -->|View Stats| J[RepresentativesPage]
J -->|Display| K[Cache Statistics]
style H fill:#e1f5ff
style F fill:#fff4e1
```
## Database Models
### PostalCodeCache Model
See [PostalCodeCache Model Documentation](../../database/models/postal-code-cache.md) for full schema.
**Key Fields:**
| Field | Type | Description |
|-------|------|-------------|
| `postalCode` | String | Normalized postal code (primary key) |
| `latitude` | Float | Centroid latitude |
| `longitude` | Float | Centroid longitude |
| `city` | String? | City name |
| `province` | String? | Province abbreviation |
**Indexes:**
- `postalCode` — Primary key, unique constraint
**Related Models:**
- [Representative](../../database/models/representative.md) — Uses postal codes for caching
- [Location](../../database/models/location.md) — Uses postal codes for geocoding
## API Endpoints
### Admin Endpoints
| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| GET | `/api/postal-codes/stats` | SUPER_ADMIN, INFLUENCE_ADMIN | Get cache statistics |
| POST | `/api/postal-codes/lookup` | SUPER_ADMIN, INFLUENCE_ADMIN | Manual postal code lookup |
### Public Endpoints
Postal code lookups are performed automatically via representative lookup (no direct public access).
## Configuration
### Environment Variables
| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `GEOCODING_PROVIDER` | string | nominatim | Default geocoding provider |
| `GEOCODING_FALLBACK_PROVIDERS` | string | - | Comma-separated fallback providers |
## Admin Workflow
### 1. View Cache Statistics
**Steps:**
1. Navigate to **Influence > Representatives**
2. View postal code cache statistics
3. Monitor cache hit rate
## Public Workflow
Postal code caching is automatic and transparent to public users.
## Code Examples
### Backend: Postal Code Caching
```typescript
// api/src/modules/influence/postal-codes/postal-codes.service.ts
export class PostalCodeService {
async getOrCreateCache(postalCode: string): Promise<PostalCodeCache> {
const normalized = postalCode.toUpperCase().replace(/\s/g, '');
// Check cache
const cached = await prisma.postalCodeCache.findUnique({
where: { postalCode: normalized }
});
if (cached) {
return cached;
}
// Geocode postal code
const result = await geocodingService.geocode({
query: postalCode,
country: 'CA'
});
if (!result) {
throw new Error('Failed to geocode postal code');
}
// Create cache entry
return prisma.postalCodeCache.create({
data: {
postalCode: normalized,
latitude: result.latitude,
longitude: result.longitude,
city: result.city,
province: result.province
}
});
}
}
```
## Related Documentation
- [Representatives Module](../../backend/modules/representatives.md)
- [Geocoding Service](../map/geocoding.md)