|
| 1 | +# Post View Geo-IP Enrichment |
| 2 | + |
| 3 | +This document captures the plan for persisting client IP/user agent info on `POST /post/v1/track_view` and enriching those records asynchronously so future analytics can segment by geography or device. |
| 4 | + |
| 5 | +## Current State |
| 6 | +- Handler signature only accepts `(State, AuthSession, Path<post_id>)` and calls `post::Entity::increment_view_count(..., None, None)`. |
| 7 | +- Global middleware already attaches `ClientIp` via `ip_config.ip_source.into_extension()` so the resolved IP is available in the request context. |
| 8 | +- `post_views` table stores `ip_address` and `user_agent` columns (both `Option<String>`) but they remain `NULL`. |
| 9 | + |
| 10 | +## Proposed Flow |
| 11 | +1. **Request Capture** |
| 12 | + - Update `track_view` handler to accept `Extension<ClientIp>` (and optionally `TypedHeader<UserAgent>`). |
| 13 | + - Extract `ip_string` (respecting forwarded headers) and the user agent header. |
| 14 | + - Pass both values into `post::Entity::increment_view_count`. |
| 15 | + |
| 16 | +2. **Persistence Updates** |
| 17 | + - Adjust `increment_view_count` signature to accept `ip_address: Option<String>` and `user_agent: Option<String>` (matches current schema). |
| 18 | + - Ensure insert into `post_views` writes these fields. |
| 19 | + |
| 20 | +3. **Geo Enrichment Queue** |
| 21 | + - Introduce a background job (new `queue::post_view_geo`) that: |
| 22 | + - Consumes `post_views` records where `geo_country` (new nullable column) is `NULL`. |
| 23 | + - Performs a lookup via MaxMind GeoIP2 or a hosted API. |
| 24 | + - Updates the row with `country_code`, `region`, etc. |
| 25 | + - Trigger job via: |
| 26 | + - Direct enqueue after each tracked view, or |
| 27 | + - Cron/worker scanning recent `post_views`. |
| 28 | + |
| 29 | +4. **Analytics Consumption** |
| 30 | + - Extend analytics queries to join on enriched columns for country/device breakdowns. |
| 31 | + - Optionally expose aggregated endpoints (e.g., `/analytics/v1/post/view-countries`). |
| 32 | + |
| 33 | +## Open Questions |
| 34 | +- Which GeoIP provider should we standardize on? (needs env wiring + rate limits) |
| 35 | +- Do we need to anonymize IPs (e.g., hash or truncate) for privacy compliance? |
| 36 | +- How often do we process the enrichment queue (real-time vs. batch)? |
| 37 | + |
| 38 | +## Next Steps |
| 39 | +1. Implement handler + DB changes to start persisting IP/user agent. |
| 40 | +2. Add migration for geo columns (`country_code`, `subdivision`, `city`, `lookup_source`, `lookup_status`). |
| 41 | +3. Build worker/queue scaffolding (could reuse existing job runner if available). |
| 42 | +4. Document env vars + failure handling (timeouts, provider fallbacks). |
0 commit comments