mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
feat(api): add GET /api/v1/stats for dashboard widgets
Homepage's customapi widget and everything shaped like it want a handful of numbers from one request; /api/v1/trips hands out the rows, but a widget maps fields, it cannot aggregate a list. The figures come from AtlasService.getTravelStats, the same call behind the dashboard's passport card, rather than from a second count. Visited countries carries years of rules — countries reached only by a flight, layovers that do not count, countries hidden by hand — and a second implementation would disagree with the card next to it within a release. That is also why the controller sits in atlas/ and not in public-api/: PublicApiModule stays a leaf, so the route comes to the data instead. TravelStatsController next door already does this for /api/auth/travel-stats. ApiTokenGuard is provided locally rather than imported with PublicApiModule — @UseGuards instantiates a guard in the declaring controller's module, so an export would still leave its TokenService unresolvable here. last_trip means the most recently started trip, not the most recently created one, and is null while every trip is still ahead. Closes #1367
This commit is contained in:
@@ -11,6 +11,7 @@ Read trips. That is deliberate and complete:
|
||||
- list the trips you own or are a member of
|
||||
- fetch one trip with its days, places in planned order, day notes, reservations, accommodations and fellow travellers
|
||||
- read the bucket list: places the traveller wants to reach, not tied to any trip
|
||||
- read a handful of totals for a dashboard widget: trips, countries, cities, places, days, flown distance, and the last trip taken
|
||||
|
||||
It cannot write anything. An integration that reads your itinerary needs no ability to delete a place, and a key that can only read is a very different thing to hand to third-party software.
|
||||
|
||||
@@ -156,6 +157,53 @@ Places the caller wants to reach, with no trip attached. Its own endpoint becaus
|
||||
|
||||
`target_date` is an aspiration, not a booking. Entries are returned whether or not the Atlas addon is switched on: the addon governs whether TREK shows the feature, not whether the rows exist, and an endpoint whose answers change when an unrelated toggle moves is one nobody can build on.
|
||||
|
||||
### `GET /api/v1/stats`
|
||||
|
||||
Totals for a dashboard. Built for widgets like Homepage's `customapi`, which render a few numbers from one request and cannot aggregate a list themselves.
|
||||
|
||||
```json
|
||||
{
|
||||
"total_trips": 12,
|
||||
"total_countries": 23,
|
||||
"total_cities": 41,
|
||||
"total_places": 143,
|
||||
"total_days": 87,
|
||||
"total_distance_km": 84213,
|
||||
"last_trip": {
|
||||
"title": "Hokkaido in winter",
|
||||
"start_date": "2026-02-03",
|
||||
"end_date": "2026-02-14",
|
||||
"country": "JP",
|
||||
"countries": ["JP"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These are the same figures TREK's own dashboard shows, computed from the same source — a widget cannot disagree with the passport card next to it. In particular `total_countries` follows TREK's notion of *visited*: countries reached only by a flight or train count, layovers do not, and countries hidden by hand in Atlas stay hidden.
|
||||
|
||||
`last_trip` is the most recent trip that has **started** — a trip booked for next year is not one you have been on — and is `null` when every trip is still ahead. `country` is the country most of its places sit in, and is the head of `countries`, which lists them all for a trip that crossed a border. Both are empty or `null` for a trip whose places were never geocoded.
|
||||
|
||||
A Homepage widget then needs no scripting:
|
||||
|
||||
```yaml
|
||||
- TREK:
|
||||
icon: mdi-map-marker-path
|
||||
widget:
|
||||
type: customapi
|
||||
url: https://trek.example.com/api/v1/stats
|
||||
headers:
|
||||
X-API-Key: trek_your_key_here
|
||||
mappings:
|
||||
- field: total_trips
|
||||
label: Trips
|
||||
- field: total_countries
|
||||
label: Countries
|
||||
- field: total_cities
|
||||
label: Cities
|
||||
- field: last_trip.country
|
||||
label: Last
|
||||
```
|
||||
|
||||
## Notes for integrators
|
||||
|
||||
**Join on dates, not ids.** Every day carries an ISO `date`, and accommodations carry a resolved date range rather than internal day ids. If your software keeps its own notion of a trip, the date is the one thing both sides can agree on. TREK's internal ids are not in the payload at all, by design — they would tie you to storage details that are free to change.
|
||||
|
||||
Reference in New Issue
Block a user