diff --git a/server/src/mcp/resources.ts b/server/src/mcp/resources.ts index da8454523..03c165a78 100644 --- a/server/src/mcp/resources.ts +++ b/server/src/mcp/resources.ts @@ -60,7 +60,7 @@ export function registerResources(server: McpServer, userId: number, scopes: str // src/nest/reservations/reservations.mcp.ts (@ResourceTemplate). // The day-notes resource moved to the DI-discovered - // src/nest/days/day-notes.mcp.ts (@ResourceTemplate). + // src/nest/day-notes/day-notes.mcp.ts (@ResourceTemplate). // The trip-accommodations resource moved to the DI-discovered // src/nest/days/days.mcp.ts (@ResourceTemplate). diff --git a/server/src/nest/app.module.ts b/server/src/nest/app.module.ts index a91ccada9..db12f8d87 100644 --- a/server/src/nest/app.module.ts +++ b/server/src/nest/app.module.ts @@ -21,6 +21,7 @@ import { PackingModule } from './packing/packing.module'; import { BudgetModule } from './budget/budget.module'; import { ReservationsModule } from './reservations/reservations.module'; import { DaysModule } from './days/days.module'; +import { DayNotesModule } from './day-notes/day-notes.module'; import { AssignmentsModule } from './assignments/assignments.module'; import { PlacesModule } from './places/places.module'; import { TripsModule } from './trips/trips.module'; @@ -60,7 +61,7 @@ import { IdempotencyInterceptor } from './common/idempotency.interceptor'; * migrated. */ @Module({ - imports: [AppConfigModule, DatabaseModule, RealtimeModule, McpModule.forRoot({ accessPolicy: trekMcpAccessPolicy, validateAccess: trekMcpValidateAccess }), HealthModule, WeatherModule, HelpModule, AirportsModule, ConfigModule, SystemNoticesModule, MapsModule, PlaceEnrichmentModule, CategoriesModule, TagsModule, NotificationsModule, AtlasModule, VacayModule, PackingModule, TodoModule, BudgetModule, ReservationsModule, DaysModule, AssignmentsModule, PlacesModule, TripsModule, CollabModule, FilesModule, PhotosModule, MemoriesModule, AirtrailModule, JourneyModule, CollectionsModule, ShareModule, TripInviteModule, TransitModule, FeedsModule, SettingsModule, BackupModule, AuthModule, OidcModule, OauthModule, AdminModule, AddonsModule, AuditModule, PermissionsModule, PluginsModule, BookingImportModule, LlmParseModule], + imports: [AppConfigModule, DatabaseModule, RealtimeModule, McpModule.forRoot({ accessPolicy: trekMcpAccessPolicy, validateAccess: trekMcpValidateAccess }), HealthModule, WeatherModule, HelpModule, AirportsModule, ConfigModule, SystemNoticesModule, MapsModule, PlaceEnrichmentModule, CategoriesModule, TagsModule, NotificationsModule, AtlasModule, VacayModule, PackingModule, TodoModule, BudgetModule, ReservationsModule, DaysModule, DayNotesModule, AssignmentsModule, PlacesModule, TripsModule, CollabModule, FilesModule, PhotosModule, MemoriesModule, AirtrailModule, JourneyModule, CollectionsModule, ShareModule, TripInviteModule, TransitModule, FeedsModule, SettingsModule, BackupModule, AuthModule, OidcModule, OauthModule, AdminModule, AddonsModule, AuditModule, PermissionsModule, PluginsModule, BookingImportModule, LlmParseModule], providers: [ // Global error-envelope normaliser (DI-registered so it also catches // framework-level exceptions like the not-found handler). diff --git a/server/src/nest/days/day-notes.controller.ts b/server/src/nest/day-notes/day-notes.controller.ts similarity index 100% rename from server/src/nest/days/day-notes.controller.ts rename to server/src/nest/day-notes/day-notes.controller.ts diff --git a/server/src/nest/days/day-notes.dto.ts b/server/src/nest/day-notes/day-notes.dto.ts similarity index 100% rename from server/src/nest/days/day-notes.dto.ts rename to server/src/nest/day-notes/day-notes.dto.ts diff --git a/server/src/nest/days/day-notes.mcp.ts b/server/src/nest/day-notes/day-notes.mcp.ts similarity index 100% rename from server/src/nest/days/day-notes.mcp.ts rename to server/src/nest/day-notes/day-notes.mcp.ts diff --git a/server/src/nest/day-notes/day-notes.module.ts b/server/src/nest/day-notes/day-notes.module.ts new file mode 100644 index 000000000..8a3f55446 --- /dev/null +++ b/server/src/nest/day-notes/day-notes.module.ts @@ -0,0 +1,28 @@ +import { Module } from '@nestjs/common'; +import { DayNotesController } from './day-notes.controller'; +import { DayNotesService } from './day-notes.service'; +import { DayNotesMcp } from './day-notes.mcp'; +import { DayNotesRpc } from './day-notes.rpc'; +import { PermissionsModule } from '../permissions/permissions.module'; +import { AuthModule } from '../auth/auth.module'; +import { RealtimeModule } from '../realtime/realtime.module'; +import { PluginGuardsModule } from '../plugins/host/plugin-guards.module'; + +/** + * Day notes. Its own domain rather than a second file set inside days/, which + * carried two fachlichkeiten with a full controller/service/mcp/rpc/dto each. + * + * Deliberately unconnected to DaysModule in both directions: `dayExists` is raw + * SQL on `days` here, and DaysService reads `day_notes` the same way. Wiring the + * modules to each other would buy nothing and cost a cycle. + * + * AuthModule is only for DayNotesMcp's demo-user gate, PluginGuardsModule only + * for DayNotesRpc. + */ +@Module({ + imports: [PermissionsModule, AuthModule, RealtimeModule, PluginGuardsModule], + controllers: [DayNotesController], + providers: [DayNotesService, DayNotesMcp, DayNotesRpc], + exports: [DayNotesService], +}) +export class DayNotesModule {} diff --git a/server/src/nest/days/day-notes.rpc.ts b/server/src/nest/day-notes/day-notes.rpc.ts similarity index 100% rename from server/src/nest/days/day-notes.rpc.ts rename to server/src/nest/day-notes/day-notes.rpc.ts diff --git a/server/src/nest/days/day-notes.service.ts b/server/src/nest/day-notes/day-notes.service.ts similarity index 100% rename from server/src/nest/days/day-notes.service.ts rename to server/src/nest/day-notes/day-notes.service.ts diff --git a/server/src/nest/days/days.module.ts b/server/src/nest/days/days.module.ts index 5bdb9b4a0..c3ed54524 100644 --- a/server/src/nest/days/days.module.ts +++ b/server/src/nest/days/days.module.ts @@ -2,32 +2,28 @@ import { Module } from '@nestjs/common'; import { DaysController } from './days.controller'; import { DaysService } from './days.service'; import { DaysMcp } from './days.mcp'; -import { DayNotesController } from './day-notes.controller'; -import { DayNotesService } from './day-notes.service'; -import { DayNotesRpc } from './day-notes.rpc'; import { DaysRpc } from './days.rpc'; import { AccommodationsRpc } from './accommodations.rpc'; import { PluginGuardsModule } from '../plugins/host/plugin-guards.module'; import { RealtimeModule } from '../realtime/realtime.module'; -import { DayNotesMcp } from './day-notes.mcp'; import { PermissionsModule } from '../permissions/permissions.module'; import { QueryHelpersModule } from '../query-helpers/query-helpers.module'; import { PlacesModule } from '../places/places.module'; import { AuthModule } from '../auth/auth.module'; /** - * Days + day-notes domain (S6 — Phase 2 trip sub-domain). The single prefix - * /api/trips/:tripId/days covers both the days mount and the nested - * /days/:dayId/notes mount. DaysMcp/DayNotesMcp carry the - * decorator-registered MCP tools + resources. DaysService and DayNotesService - * are exported for in-container consumers (DaysRpc, DayNotesRpc, - * AccommodationsService, TripsService, the assignments/reservations MCP - * controllers). + * Days (S6 — Phase 2 trip sub-domain), mounted at /api/trips/:tripId/days. + * DaysMcp carries the decorator-registered MCP tools + resources. DaysService is + * exported for in-container consumers (DaysRpc, AccommodationsService, + * TripsService, the assignments/reservations MCP controllers). + * + * Day notes used to live here too, with their own full file set; they are their + * own domain now (day-notes/). */ @Module({ imports: [PermissionsModule, QueryHelpersModule, PlacesModule, AuthModule, RealtimeModule, PluginGuardsModule], - controllers: [DaysController, DayNotesController], - providers: [DaysService, DaysMcp, DayNotesService, DayNotesMcp, DayNotesRpc, DaysRpc, AccommodationsRpc], - exports: [DaysService, DayNotesService], + controllers: [DaysController], + providers: [DaysService, DaysMcp, DaysRpc, AccommodationsRpc], + exports: [DaysService], }) export class DaysModule {} diff --git a/server/src/nest/plugins/plugins-runtime.module.ts b/server/src/nest/plugins/plugins-runtime.module.ts index 80324bb12..94c6c0da3 100644 --- a/server/src/nest/plugins/plugins-runtime.module.ts +++ b/server/src/nest/plugins/plugins-runtime.module.ts @@ -20,6 +20,7 @@ import { ReservationsModule } from '../reservations/reservations.module'; import { TodoModule } from '../todo/todo.module'; import { PackingModule } from '../packing/packing.module'; import { DaysModule } from '../days/days.module'; +import { DayNotesModule } from '../day-notes/day-notes.module'; import { AssignmentsModule } from '../assignments/assignments.module'; import { LlmParseModule } from '../llm-parse/llm-parse.module'; import { FilesModule } from '../files/files.module'; @@ -61,7 +62,7 @@ import { JourneyDomainModule } from '../journey/journey-domain.module'; PluginGuardsModule, PluginOAuthModule, WeatherModule, TagsModule, CategoriesModule, BudgetModule, ReservationsModule, - TodoModule, PackingModule, DaysModule, AssignmentsModule, LlmParseModule, + TodoModule, PackingModule, DaysModule, DayNotesModule, AssignmentsModule, LlmParseModule, FilesModule, CollabModule, VacayModule, TripsModule, PlacesModule, PermissionsModule, AuditModule, AddonsModule, CollectionsModule, AtlasModule, NotificationsModule, TripMembershipModule, JourneyDomainModule, diff --git a/server/tests/e2e/days.e2e.test.ts b/server/tests/e2e/days.e2e.test.ts index e625c5802..4c1bf5934 100644 --- a/server/tests/e2e/days.e2e.test.ts +++ b/server/tests/e2e/days.e2e.test.ts @@ -81,6 +81,10 @@ import { PermissionsService } from '../../src/nest/permissions/permissions.servi let checkPermission: MockInstance; import { DaysModule } from '../../src/nest/days/days.module'; +// The note routes nest under the days prefix but live in their own domain now; +// this container has to assemble both or /days/:dayId/notes 404s here while +// working in production. +import { DayNotesModule } from '../../src/nest/day-notes/day-notes.module'; import { TrekExceptionFilter } from '../../src/nest/common/trek-exception.filter'; import { ZodValidationPipe } from '../../src/nest/common/zod-validation.pipe'; @@ -89,7 +93,7 @@ describe('Days + day-notes e2e (real auth guard + temp SQLite, real day SQL)', ( let app: Awaited>; async function build() { - const moduleRef = await Test.createTestingModule({ imports: [DatabaseModule, RealtimeModule, DaysModule] }).compile(); + const moduleRef = await Test.createTestingModule({ imports: [DatabaseModule, RealtimeModule, DaysModule, DayNotesModule] }).compile(); const nest = moduleRef.createNestApplication(); nest.use(cookieParser()); nest.useGlobalPipes(new ZodValidationPipe()); diff --git a/server/tests/helpers/mcp-test-controllers.ts b/server/tests/helpers/mcp-test-controllers.ts index 9db4b6a53..4210d521a 100644 --- a/server/tests/helpers/mcp-test-controllers.ts +++ b/server/tests/helpers/mcp-test-controllers.ts @@ -16,8 +16,8 @@ import { CollabService } from '../../src/nest/collab/collab.service'; import { CollectionsMcp } from '../../src/nest/collections/collections.mcp'; import { CollectionsService } from '../../src/nest/collections/collections.service'; import { DatabaseService } from '../../src/nest/database/database.service'; -import { DayNotesMcp } from '../../src/nest/days/day-notes.mcp'; -import { DayNotesService } from '../../src/nest/days/day-notes.service'; +import { DayNotesMcp } from '../../src/nest/day-notes/day-notes.mcp'; +import { DayNotesService } from '../../src/nest/day-notes/day-notes.service'; import { DaysMcp } from '../../src/nest/days/days.mcp'; import { DaysService } from '../../src/nest/days/days.service'; import { MapsMcp } from '../../src/nest/maps/maps.mcp'; diff --git a/server/tests/helpers/plugin-host.ts b/server/tests/helpers/plugin-host.ts index 5548b123f..52f7e6d27 100644 --- a/server/tests/helpers/plugin-host.ts +++ b/server/tests/helpers/plugin-host.ts @@ -18,7 +18,7 @@ import { TagsService } from '../../src/nest/tags/tags.service'; import { CategoriesService } from '../../src/nest/categories/categories.service'; import { TodoService } from '../../src/nest/todo/todo.service'; import { PackingService } from '../../src/nest/packing/packing.service'; -import { DayNotesService } from '../../src/nest/days/day-notes.service'; +import { DayNotesService } from '../../src/nest/day-notes/day-notes.service'; import { DaysService } from '../../src/nest/days/days.service'; import { AssignmentsService } from '../../src/nest/assignments/assignments.service'; import { LlmConfigResolver } from '../../src/nest/llm-parse/llm-config.resolver'; @@ -44,7 +44,7 @@ import { WeatherRpc } from '../../src/nest/weather/weather.rpc'; import { WeatherService } from '../../src/nest/weather/weather.service'; import { ExchangeRatesRpc } from '../../src/nest/budget/exchange-rates.rpc'; import { TodoRpc } from '../../src/nest/todo/todo.rpc'; -import { DayNotesRpc } from '../../src/nest/days/day-notes.rpc'; +import { DayNotesRpc } from '../../src/nest/day-notes/day-notes.rpc'; import { PackingRpc } from '../../src/nest/packing/packing.rpc'; import { FilesRpc } from '../../src/nest/files/files.rpc'; import { PlacesRpc } from '../../src/nest/places/places.rpc'; diff --git a/server/tests/helpers/rpc-host-deps.ts b/server/tests/helpers/rpc-host-deps.ts index b18d5379e..6eb109451 100644 --- a/server/tests/helpers/rpc-host-deps.ts +++ b/server/tests/helpers/rpc-host-deps.ts @@ -5,7 +5,7 @@ import { CategoriesRpc } from '../../src/nest/categories/categories.rpc'; import { WeatherRpc } from '../../src/nest/weather/weather.rpc'; import { ExchangeRatesRpc } from '../../src/nest/budget/exchange-rates.rpc'; import { TodoRpc } from '../../src/nest/todo/todo.rpc'; -import { DayNotesRpc } from '../../src/nest/days/day-notes.rpc'; +import { DayNotesRpc } from '../../src/nest/day-notes/day-notes.rpc'; import { PackingRpc } from '../../src/nest/packing/packing.rpc'; import { FilesRpc } from '../../src/nest/files/files.rpc'; import { PlacesRpc } from '../../src/nest/places/places.rpc'; diff --git a/server/tests/unit/days/day-notes.rpc.test.ts b/server/tests/unit/days/day-notes.rpc.test.ts index 50d8bec24..2e1994f64 100644 --- a/server/tests/unit/days/day-notes.rpc.test.ts +++ b/server/tests/unit/days/day-notes.rpc.test.ts @@ -9,9 +9,9 @@ import { expectRegisteredProvider } from '../../helpers/module-providers'; import { PluginRpcHost } from '../../../src/nest/plugins/host/rpc-host'; import { createTestPluginRegistry } from '../../../src/nest/plugins/host/rpc-kit/testing'; import { PluginGuards } from '../../../src/nest/plugins/host/plugin-guards.service'; -import { DayNotesRpc } from '../../../src/nest/days/day-notes.rpc'; -import { DaysModule } from '../../../src/nest/days/days.module'; -import type { DayNotesService } from '../../../src/nest/days/day-notes.service'; +import { DayNotesRpc } from '../../../src/nest/day-notes/day-notes.rpc'; +import { DayNotesModule } from '../../../src/nest/day-notes/day-notes.module'; +import type { DayNotesService } from '../../../src/nest/day-notes/day-notes.service'; import type { RealtimeService } from '../../../src/nest/realtime/realtime.service'; import type { DatabaseService } from '../../../src/nest/database/database.service'; import type { PermissionsService } from '../../../src/nest/permissions/permissions.service'; @@ -115,6 +115,6 @@ describe('DayNotesRpc through the router', () => { }); it('DAYNOTES-RPC-009 the class is listed in its module providers', () => { - expectRegisteredProvider(DaysModule, DayNotesRpc); + expectRegisteredProvider(DayNotesModule, DayNotesRpc); }); }); diff --git a/server/tests/unit/nest/day-notes.service.test.ts b/server/tests/unit/nest/day-notes.service.test.ts index 334ede046..356f096fa 100644 --- a/server/tests/unit/nest/day-notes.service.test.ts +++ b/server/tests/unit/nest/day-notes.service.test.ts @@ -48,7 +48,7 @@ import { resetTestDb } from '../../helpers/test-db'; import { createUser, createTrip, createDay, addTripMember } from '../../helpers/factories'; import { DatabaseService } from '../../../src/nest/database/database.service'; import { PermissionsService } from '../../../src/nest/permissions/permissions.service'; -import { DayNotesService } from '../../../src/nest/days/day-notes.service'; +import { DayNotesService } from '../../../src/nest/day-notes/day-notes.service'; import type { DayNote } from '../../../src/types'; import { RealtimeService } from '../../../src/nest/realtime/realtime.service'; diff --git a/server/tests/unit/nest/days.controller.test.ts b/server/tests/unit/nest/days.controller.test.ts index e9407157a..5b88a3c01 100644 --- a/server/tests/unit/nest/days.controller.test.ts +++ b/server/tests/unit/nest/days.controller.test.ts @@ -1,11 +1,11 @@ import { describe, it, expect, vi } from 'vitest'; import { HttpException } from '@nestjs/common'; import { DaysController } from '../../../src/nest/days/days.controller'; -import { DayNotesController } from '../../../src/nest/days/day-notes.controller'; -import { DayNoteCreateDto, DayNoteUpdateDto } from '../../../src/nest/days/day-notes.dto'; +import { DayNotesController } from '../../../src/nest/day-notes/day-notes.controller'; +import { DayNoteCreateDto, DayNoteUpdateDto } from '../../../src/nest/day-notes/day-notes.dto'; import { DayReorderError } from '../../../src/nest/days/days.service'; import type { DaysService } from '../../../src/nest/days/days.service'; -import type { DayNotesService } from '../../../src/nest/days/day-notes.service'; +import type { DayNotesService } from '../../../src/nest/day-notes/day-notes.service'; import type { User } from '../../../src/types'; const user = { id: 1, role: 'user', email: 'u@example.test' } as User; diff --git a/server/tests/unit/plugins/rpc-fallbacks.test.ts b/server/tests/unit/plugins/rpc-fallbacks.test.ts index e04165965..59954674d 100644 --- a/server/tests/unit/plugins/rpc-fallbacks.test.ts +++ b/server/tests/unit/plugins/rpc-fallbacks.test.ts @@ -13,7 +13,7 @@ import { PluginRpcHost } from '../../../src/nest/plugins/host/rpc-host'; import { createTestPluginRegistry } from '../../../src/nest/plugins/host/rpc-kit/testing'; import { PluginGuards } from '../../../src/nest/plugins/host/plugin-guards.service'; import { TagsRpc } from '../../../src/nest/tags/tags.rpc'; -import { DayNotesRpc } from '../../../src/nest/days/day-notes.rpc'; +import { DayNotesRpc } from '../../../src/nest/day-notes/day-notes.rpc'; import { PlacesRpc } from '../../../src/nest/places/places.rpc'; import { PackingRpc } from '../../../src/nest/packing/packing.rpc'; import { FilesRpc } from '../../../src/nest/files/files.rpc'; diff --git a/server/vitest.config.ts b/server/vitest.config.ts index cc4068213..133d5eef0 100644 --- a/server/vitest.config.ts +++ b/server/vitest.config.ts @@ -79,6 +79,7 @@ export default defineConfig({ 'src/nest/common/**/*.ts': { statements: 95, branches: 89, functions: 99, lines: 97 }, 'src/nest/config/**/*.ts': { statements: 99, branches: 100, functions: 99, lines: 99 }, 'src/nest/database/**/*.ts': { statements: 99, branches: 100, functions: 99, lines: 99 }, + 'src/nest/day-notes/**/*.ts': { statements: 92, branches: 82, functions: 98, lines: 97 }, 'src/nest/days/**/*.ts': { statements: 92, branches: 82, functions: 98, lines: 97 }, 'src/nest/feeds/**/*.ts': { statements: 91, branches: 83, functions: 83, lines: 91 }, 'src/nest/files/**/*.ts': { statements: 97, branches: 95, functions: 99, lines: 98 },