refactor(server): consolidate trip access and fold the query helpers into the container (#1824)

* refactor(server): route every trip-access check through DatabaseService

Twelve Nest services carry the same verifyTripAccess/canEdit pair. Six already
asked DatabaseService.canAccessTrip; the other six went through
services/tripAccess, a nine-line re-export of the identical function. Same
query, same result, two ways to reach it.

All twelve now take the injected route, so services/tripAccess is gone.

The bigger duplication was in the types. Thirteen files declared their own
`Trip` for the same return value, in three different shapes:

  NonNullable<ReturnType<typeof verifyTripAccess>>   6x
  { user_id: number }                                4x
  TripAccess                                         3x

The narrow one is why assignments, days, places and accommodations all wrote
`as Trip | null | undefined` on the call — the cast existed to shrink
TripAccess down to a local type that was never meant to differ from it. All
thirteen now say TripAccess, and the four casts are gone with no other change.

middleware/tripAccess.ts goes too: it was already dead in production — nothing
under src/ imported requireTripAccess or requireTripOwner, only comments in the
services that had absorbed them. Its test went with it.

* refactor(server): fold the query helpers and trip joins into the container

Two more legacy files whose only reason for staying outside the container was
that they predated it.

services/queryHelpers.ts held five exports doing two different jobs. Three are
the batch loaders that keep the list endpoints off N+1 queries — they hit the
database and are now QueryHelpersService over the injected connection, imported
by assignments, days, places and share. The other two, formatAssignmentWithPlace
and ratingAggregate, touch no database at all; they sat next to the loaders only
because the loaders were free functions too. Those stay free functions, in
common/rowShape.ts.

The README note on the assignments service claimed the loaders had to stay in
services/ because the day, share and place services were unmigrated. All three
have since moved, so the reason is gone.

services/tripMembership.ts becomes TripMembershipService in its own module. It
could have folded into auth or trip-invite, but both call it — as do oidc and
the plugin RPC host — and putting it in either would have made AuthModule and
TripInviteModule import each other.

Neither module is @Global, matching PermissionsModule: e2e TestingModules
resolve them transitively through each consumer's explicit import.

Test seams changed shape accordingly. Two path mocks of services/tripMembership
became injected stubs; the trip-invite e2e overrides the provider in the
container instead. The oidc test keeps the real implementation, which is what
OIDC-SVC-045 was always asserting.

ratingAggregate moved out of the ungated services/ tree into the coverage-gated
one, so it gets the direct tests it never had — as does the tags/participants
pass-through, which two long-dead fixture variables in the moved test file had
been waiting for.

Also drops four stale comments that outlived their subject: the requireTripAccess
middleware they pointed at was deleted in the previous commit.
This commit is contained in:
Maurice
2026-08-07 16:00:12 +02:00
committed by GitHub
parent 6dda05f672
commit 939452f9d8
59 changed files with 424 additions and 477 deletions
+6 -4
View File
@@ -46,6 +46,7 @@ import { TripsService } from '../../src/nest/trips/trips.service';
import { VacayMcp } from '../../src/nest/vacay/vacay.mcp';
import { VacayService } from '../../src/nest/vacay/vacay.service';
import { RealtimeService } from '../../src/nest/realtime/realtime.service';
import { QueryHelpersService } from '../../src/nest/query-helpers/query-helpers.service';
/**
* Hand-wired counterpart of the boot-time discovery in McpRegistryService,
@@ -59,14 +60,15 @@ export function createMcpTestRegistry(): McpRegistry {
const permissionsService = new PermissionsService(dbService);
const authService = new AuthService(dbService, permissionsService, new AtlasService(dbService));
const realtimeService = new RealtimeService();
const daysService = new DaysService(dbService, permissionsService, realtimeService);
const queryHelpersService = new QueryHelpersService(dbService);
const daysService = new DaysService(dbService, permissionsService, realtimeService, queryHelpersService);
const exchangeRatesService = new ExchangeRatesService();
const budgetService = new BudgetService(dbService, permissionsService, exchangeRatesService, realtimeService);
const todoService = new TodoService(dbService, permissionsService, realtimeService);
const packingService = new PackingService(dbService, permissionsService, realtimeService);
const collabService = new CollabService(dbService, permissionsService, realtimeService);
const mapsService = new MapsService(dbService);
const placesService = new PlacesService(dbService, permissionsService, realtimeService, mapsService);
const placesService = new PlacesService(dbService, permissionsService, realtimeService, mapsService, queryHelpersService);
const reservationsService = new ReservationsService(dbService, permissionsService, budgetService, realtimeService);
const tripsService = new TripsService(
dbService,
@@ -92,11 +94,11 @@ export function createMcpTestRegistry(): McpRegistry {
new ReservationsMcp(reservationsService, daysService, budgetService, authService),
new DayNotesMcp(new DayNotesService(dbService, permissionsService, realtimeService), authService),
new DaysMcp(daysService, dbService, placesService, authService),
new AssignmentsMcp(new AssignmentsService(dbService, permissionsService, realtimeService), daysService, authService),
new AssignmentsMcp(new AssignmentsService(dbService, permissionsService, realtimeService, queryHelpersService), daysService, authService),
new CollabMcp(collabService, authService),
new VacayMcp(new VacayService(dbService, realtimeService), authService),
new TripsMcp(tripsService, todoService, collabService, authService),
new ShareMcp(new ShareService(dbService, new SettingsService(dbService), permissionsService), authService),
new ShareMcp(new ShareService(dbService, new SettingsService(dbService), permissionsService, queryHelpersService), authService),
new MapsMcp(mapsService),
new PlacesMcp(placesService, mapsService, dbService, authService),
new CollectionsMcp(new CollectionsService(dbService, permissionsService, realtimeService), dbService, authService),