feat(api): separate API keys from MCP tokens, add travellers

An MCP token drives every assistant tool; an API key reads trips over HTTP.
Handing the same credential to a third-party integration gives it the whole
MCP surface, so the two are now separate kinds on `mcp_tokens` and the kind
sits in the WHERE clause — a token of the wrong kind is indistinguishable
from one that does not exist.

Also adds `travellers` to the trip payload: display name and an owner flag,
no ids and no email addresses. An integration key reads its owner's
itinerary; it is not a way to enumerate the people around them.

Documents the surface in the wiki, since integrators need something to read
that is not the source.
This commit is contained in:
Maurice
2026-08-28 01:29:04 +02:00
committed by Maurice
parent 9cddf683a5
commit 4b120d39c8
9 changed files with 381 additions and 20 deletions
+16 -1
View File
@@ -92,6 +92,20 @@ export const publicApiDaySchema = z.object({
});
export type PublicApiDay = z.infer<typeof publicApiDaySchema>;
/**
* Someone who is on the trip.
*
* Display name only. Ids would let a consumer correlate the same person across
* instances, and email addresses have no business leaving TREK over an
* integration key — the name is what a traveller already sees on the trip.
*/
export const publicApiTravellerSchema = z.object({
name: z.string(),
/** True for the trip's owner; everyone else joined as a member. */
owner: z.boolean(),
});
export type PublicApiTraveller = z.infer<typeof publicApiTravellerSchema>;
/** Trip without its itinerary — what the list endpoint returns. */
export const publicApiTripSummarySchema = z.object({
id: z.number(),
@@ -121,6 +135,7 @@ export type PublicApiTripSummary = z.infer<typeof publicApiTripSummarySchema>;
export const publicApiTripSchema = publicApiTripSummarySchema.extend({
days: z.array(publicApiDaySchema).optional(),
accommodations: z.array(publicApiAccommodationSchema).optional(),
travellers: z.array(publicApiTravellerSchema).optional(),
});
export type PublicApiTrip = z.infer<typeof publicApiTripSchema>;
@@ -129,7 +144,7 @@ export type PublicApiTrip = z.infer<typeof publicApiTripSchema>;
* case is a full sync; a consumer that only wants notes says so and gets a payload
* a fraction of the size.
*/
export const PUBLIC_API_INCLUDES = ['days', 'places', 'notes', 'reservations', 'accommodations'] as const;
export const PUBLIC_API_INCLUDES = ['days', 'places', 'notes', 'reservations', 'accommodations', 'travellers'] as const;
export type PublicApiInclude = (typeof PUBLIC_API_INCLUDES)[number];
/**