docs: add apilog design spec
This commit is contained in:
53
docs/superpowers/specs/2026-04-04-apilog-design.md
Normal file
53
docs/superpowers/specs/2026-04-04-apilog-design.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# API Log Design
|
||||
|
||||
**Date:** 2026-04-04
|
||||
**Scope:** Outbound HTTP request logging only. Inbound request logging is out of scope (separate table `request_logs` when needed).
|
||||
|
||||
## Purpose
|
||||
|
||||
Log every outbound HTTP request made by this application to external APIs. Provides an audit trail for debugging failed polls, tracking latency, and monitoring API health over time.
|
||||
|
||||
## Table: `api_logs`
|
||||
|
||||
| Column | Type | Nullable | Notes |
|
||||
|---|---|---|---|
|
||||
| `id` | BIGINT UNSIGNED | no | Auto-increment PK |
|
||||
| `service` | VARCHAR(32) | no | Identifies the external service: `fuel_finder`, `fred`, `postcodes_io`, `vonage`, `onesignal` |
|
||||
| `method` | VARCHAR(8) | no | HTTP method: `GET`, `POST` |
|
||||
| `url` | VARCHAR(512) | no | Full URL including query string |
|
||||
| `status_code` | SMALLINT UNSIGNED | yes | HTTP response status code; null if request threw an exception |
|
||||
| `duration_ms` | SMALLINT UNSIGNED | no | Round-trip response time in milliseconds |
|
||||
| `error` | TEXT | yes | Exception message if the request failed; null on success |
|
||||
| `created_at` | DATETIME | no | When the request was made |
|
||||
|
||||
No `updated_at` — rows are write-once.
|
||||
|
||||
## ApiLogger Service
|
||||
|
||||
A thin `ApiLogger` service wraps Laravel's `Http::` facade. It:
|
||||
|
||||
1. Records start time
|
||||
2. Makes the HTTP request inside a try/catch
|
||||
3. Writes an `api_logs` row with URL, status, duration, and error (if any) — always, via try/finally
|
||||
4. Re-throws any exception so the calling service retains full control over error handling
|
||||
|
||||
`FuelPriceService` (and future services hitting external APIs) inject `ApiLogger` and use it instead of calling `Http::` directly.
|
||||
|
||||
## What Gets Logged
|
||||
|
||||
Every outbound GET and POST — including:
|
||||
- Fuel Finder OAuth token requests (`POST /oauth/generate_access_token`)
|
||||
- Fuel Finder price batch fetches (`GET /pfs/fuel-prices?batch-number=N`)
|
||||
- Fuel Finder station metadata fetches (`GET /pfs?batch-number=N`)
|
||||
- Future: FRED Brent crude fetch, Postcodes.io lookups, Vonage, OneSignal
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Response body storage (not logged — too large, not needed)
|
||||
- Request headers or credentials (never logged)
|
||||
- Inbound request logging (`request_logs` — separate feature)
|
||||
- Relation between `api_logs` and `station_prices` rows
|
||||
|
||||
## Pruning
|
||||
|
||||
Old rows can be pruned on a schedule (e.g. keep 30 days). Not in scope for this implementation but the table should support it via `created_at` index.
|
||||
Reference in New Issue
Block a user