mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 07:53:09 +00:00
feat(api): rate-limit /api/v1 and report when a trip last changed
Two gaps from the first pass, both about a client that polls. Rate limiting is keyed by user rather than by IP. A self-hosted integration and its owner's browser routinely leave the same address, and an IP bucket would let one starve the other; 120 requests a minute is generous for a sync surface and still bounded, so a runaway poll degrades its own integration instead of the instance. updated_at now ships with every trip, and its docblock says plainly what it is not: a content timestamp. It moves when the trip's own fields change — title, dates, currency, cover — and stays put when a place, a day or a note is edited, because the child tables carry no updated_at of their own. That also rules out the ?since= filter this was meant to enable: it would silently hide every trip whose itinerary changed, which is worse than no filter at all. Making it honest needs a schema change, not an API field, so the field is documented for what it is and the filter is left out.
This commit is contained in:
@@ -101,6 +101,15 @@ export const publicApiTripSummarySchema = z.object({
|
||||
end_date: z.string().nullable(),
|
||||
currency: z.string().nullable(),
|
||||
archived: z.boolean(),
|
||||
/**
|
||||
* When the trip's own fields last changed — title, dates, currency, cover.
|
||||
*
|
||||
* Explicitly NOT a content timestamp: editing a place, a day or a note does not
|
||||
* touch it, because the child tables carry no `updated_at` of their own. A client
|
||||
* that polls must compare the payload it received, not this value; using it to
|
||||
* skip a fetch would silently miss every itinerary edit.
|
||||
*/
|
||||
updated_at: z.string().nullable(),
|
||||
});
|
||||
export type PublicApiTripSummary = z.infer<typeof publicApiTripSummarySchema>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user