From 5f17a5df50118a770089dd0c4713ff6f21e65e85 Mon Sep 17 00:00:00 2001 From: Maurice Date: Thu, 8 Oct 2026 15:07:48 +0200 Subject: [PATCH] refactor(db): generate the Kysely table types from the migrated schema The repositories typed their Kysely statements against 159 table interfaces written by hand, one or more per repository. Nothing compared them with the schema: a migration that renamed a column or changed its type left them stale while tsc stayed green, and several had already drifted (reservations.accommodation_id is TEXT, not INTEGER). scripts/generate-db-types.ts migrates a throwaway database with the real migrations, reads every table back and writes one interface per table into src/db/kysely/ plus the DB map in db.ts. Every hand-written interface is now Pick of that type, and npm run check:db-types fails when the committed files no longer match the migrations. A column an insert may leave out (rowid, DEFAULT, nullable) is InsertOptional, declared as ColumnType. The server compiles without strictNullChecks, where Kysely's own Generated still demands the column; that is why the old code kept separate insert-only interfaces. The ids callers pass as number | string are cast to the column type at the bind, so every statement binds the same value as before. --- CLAUDE.md | 2 +- server/CLAUDE.md | 4 +- server/package.json | 2 + server/scripts/generate-db-types.ts | 259 ++++++++++++++++ server/scripts/generate-entities.ts | 4 +- server/scripts/size-baseline.json | 7 +- server/src/db/kysely/Addons.table.ts | 15 + server/src/db/kysely/AppSettings.table.ts | 9 + .../db/kysely/AssignmentParticipants.table.ts | 10 + server/src/db/kysely/AuditLog.table.ts | 14 + server/src/db/kysely/BucketList.table.ts | 19 ++ .../db/kysely/BudgetCategoryOrder.table.ts | 10 + .../src/db/kysely/BudgetItemMembers.table.ts | 12 + .../src/db/kysely/BudgetItemPayers.table.ts | 11 + server/src/db/kysely/BudgetItems.table.ts | 24 ++ .../src/db/kysely/BudgetSettlements.table.ts | 18 ++ server/src/db/kysely/Categories.table.ts | 13 + server/src/db/kysely/CollabLinks.table.ts | 15 + .../db/kysely/CollabMessageReactions.table.ts | 12 + server/src/db/kysely/CollabMessages.table.ts | 14 + server/src/db/kysely/CollabNotes.table.ts | 18 ++ server/src/db/kysely/CollabPollVotes.table.ts | 12 + server/src/db/kysely/CollabPolls.table.ts | 16 + .../src/db/kysely/CollectionLabels.table.ts | 13 + .../src/db/kysely/CollectionMembers.table.ts | 13 + .../db/kysely/CollectionPlaceLabels.table.ts | 7 + .../db/kysely/CollectionPlaceRatings.table.ts | 12 + .../db/kysely/CollectionPlaceTags.table.ts | 7 + .../src/db/kysely/CollectionPlaces.table.ts | 33 +++ server/src/db/kysely/Collections.table.ts | 18 ++ .../db/kysely/DawarichConnections.table.ts | 18 ++ .../kysely/DawarichVisitSuggestions.table.ts | 33 +++ .../src/db/kysely/DayAccommodations.table.ts | 18 ++ server/src/db/kysely/DayAssignments.table.ts | 23 ++ server/src/db/kysely/DayNotes.table.ts | 16 + server/src/db/kysely/Days.table.ts | 14 + .../db/kysely/DocumentConnections.table.ts | 21 ++ .../db/kysely/DocumentProviderFields.table.ts | 17 ++ .../src/db/kysely/DocumentProviders.table.ts | 13 + .../src/db/kysely/DocumentSyncItems.table.ts | 28 ++ server/src/db/kysely/FileLinks.table.ts | 14 + server/src/db/kysely/GoogleApiUsage.table.ts | 9 + .../db/kysely/GooglePlacePhotoMeta.table.ts | 11 + server/src/db/kysely/HiddenCountries.table.ts | 11 + server/src/db/kysely/HiddenRegions.table.ts | 12 + server/src/db/kysely/IdempotencyKeys.table.ts | 14 + server/src/db/kysely/InviteTokens.table.ts | 15 + server/src/db/kysely/JourneyBooks.table.ts | 16 + .../db/kysely/JourneyContributors.table.ts | 12 + server/src/db/kysely/JourneyEntries.table.ts | 33 +++ .../src/db/kysely/JourneyEntryPhotos.table.ts | 11 + server/src/db/kysely/JourneyPhotos.table.ts | 17 ++ .../src/db/kysely/JourneyShareTokens.table.ts | 16 + server/src/db/kysely/JourneyTrips.table.ts | 8 + server/src/db/kysely/Journeys.table.ts | 22 ++ server/src/db/kysely/McpTokens.table.ts | 17 ++ server/src/db/kysely/Migrations.table.ts | 10 + .../NotificationChannelPreferences.table.ts | 11 + server/src/db/kysely/Notifications.table.ts | 26 ++ server/src/db/kysely/OauthClients.table.ts | 18 ++ server/src/db/kysely/OauthConsents.table.ts | 12 + server/src/db/kysely/OauthTokens.table.ts | 19 ++ .../src/db/kysely/PackingBagMembers.table.ts | 7 + server/src/db/kysely/PackingBags.table.ts | 15 + .../kysely/PackingCategoryAssignees.table.ts | 11 + .../kysely/PackingItemContributors.table.ts | 11 + .../db/kysely/PackingItemRecipients.table.ts | 7 + server/src/db/kysely/PackingItems.table.ts | 21 ++ .../kysely/PackingTemplateCategories.table.ts | 11 + .../db/kysely/PackingTemplateItems.table.ts | 14 + .../src/db/kysely/PackingTemplates.table.ts | 11 + .../db/kysely/PasswordResetTokens.table.ts | 14 + .../db/kysely/PhotoProviderFields.table.ts | 19 ++ server/src/db/kysely/PhotoProviders.table.ts | 13 + server/src/db/kysely/Photos.table.ts | 18 ++ .../src/db/kysely/PlaceDetailsCache.table.ts | 12 + server/src/db/kysely/PlaceRatings.table.ts | 12 + server/src/db/kysely/PlaceRegions.table.ts | 11 + .../src/db/kysely/PlaceShadowPicks.table.ts | 20 ++ server/src/db/kysely/PlaceTags.table.ts | 7 + server/src/db/kysely/Places.table.ts | 41 +++ server/src/db/kysely/PluginActions.table.ts | 14 + .../db/kysely/PluginCapabilityAudit.table.ts | 16 + .../src/db/kysely/PluginEgressHosts.table.ts | 11 + .../db/kysely/PluginEntityMetadata.table.ts | 14 + server/src/db/kysely/PluginErrorLog.table.ts | 13 + .../db/kysely/PluginMetaMigrations.table.ts | 10 + .../src/db/kysely/PluginOauthState.table.ts | 10 + .../src/db/kysely/PluginOauthTokens.table.ts | 14 + .../db/kysely/PluginScheduledTasks.table.ts | 14 + .../db/kysely/PluginSettingsFields.table.ts | 21 ++ .../src/db/kysely/PluginUserConfig.table.ts | 11 + .../db/kysely/PluginUserErasureQueue.table.ts | 11 + server/src/db/kysely/Plugins.table.ts | 38 +++ .../src/db/kysely/PushSubscriptions.table.ts | 17 ++ .../kysely/ReservationDayPositions.table.ts | 8 + .../db/kysely/ReservationEndpoints.table.ts | 19 ++ .../db/kysely/ReservationTravelers.table.ts | 10 + server/src/db/kysely/Reservations.table.ts | 34 +++ .../db/kysely/RoadtripDayBoundaries.table.ts | 12 + .../src/db/kysely/RoadtripDayTracks.table.ts | 11 + .../db/kysely/RoadtripPreferences.table.ts | 8 + server/src/db/kysely/RoadtripVias.table.ts | 14 + server/src/db/kysely/RouteUsageDaily.table.ts | 15 + server/src/db/kysely/SchemaVersion.table.ts | 9 + .../db/kysely/SchoolHolidayCountries.table.ts | 7 + .../db/kysely/SchoolHolidayPeriods.table.ts | 12 + .../db/kysely/SchoolHolidayRegions.table.ts | 11 + server/src/db/kysely/Settings.table.ts | 11 + server/src/db/kysely/ShareTokens.table.ts | 20 ++ server/src/db/kysely/Tags.table.ts | 12 + .../db/kysely/TodoCategoryAssignees.table.ts | 11 + server/src/db/kysely/TodoItems.table.ts | 19 ++ server/src/db/kysely/TourTypes.table.ts | 15 + server/src/db/kysely/TourWaypoints.table.ts | 13 + server/src/db/kysely/Tours.table.ts | 18 ++ .../src/db/kysely/TrekPhotoCacheMeta.table.ts | 10 + server/src/db/kysely/TrekPhotos.table.ts | 22 ++ server/src/db/kysely/TripAlbumLinks.table.ts | 17 ++ .../src/db/kysely/TripDocumentLinks.table.ts | 31 ++ server/src/db/kysely/TripFiles.table.ts | 22 ++ .../src/db/kysely/TripInviteTokens.table.ts | 13 + server/src/db/kysely/TripMembers.table.ts | 12 + server/src/db/kysely/TripPhotos.table.ts | 14 + server/src/db/kysely/Trips.table.ts | 21 ++ .../db/kysely/UserNoticeDismissals.table.ts | 11 + server/src/db/kysely/Users.table.ts | 47 +++ .../db/kysely/VacayCompanyHolidays.table.ts | 12 + server/src/db/kysely/VacayEntries.table.ts | 14 + .../db/kysely/VacayHolidayCalendars.table.ts | 14 + .../src/db/kysely/VacayPlanMembers.table.ts | 12 + server/src/db/kysely/VacayPlans.table.ts | 18 ++ server/src/db/kysely/VacayShares.table.ts | 12 + server/src/db/kysely/VacayUserColors.table.ts | 11 + .../src/db/kysely/VacayUserSettings.table.ts | 12 + server/src/db/kysely/VacayUserYears.table.ts | 13 + server/src/db/kysely/VacayYears.table.ts | 10 + .../src/db/kysely/VisitedCountries.table.ts | 12 + server/src/db/kysely/VisitedRegions.table.ts | 13 + .../src/db/kysely/WebauthnChallenges.table.ts | 13 + .../db/kysely/WebauthnCredentials.table.ts | 19 ++ server/src/db/kysely/columns.ts | 7 + server/src/db/kysely/db.ts | 277 ++++++++++++++++++ .../db/repositories/AuditLog.repository.ts | 8 +- .../db/repositories/BucketList.repository.ts | 35 +-- .../BudgetCategoryOrder.repository.ts | 5 +- .../BudgetItemMembers.repository.ts | 18 +- .../BudgetItemPayers.repository.ts | 16 +- .../db/repositories/BudgetItems.repository.ts | 42 +-- .../BudgetSettlements.repository.ts | 22 +- .../db/repositories/CollabLinks.repository.ts | 6 +- .../repositories/CollabMessages.repository.ts | 30 +- .../db/repositories/CollabNotes.repository.ts | 36 +-- .../db/repositories/CollabPolls.repository.ts | 6 +- .../CollectionLabels.repository.ts | 18 +- .../CollectionMembers.repository.ts | 28 +- .../CollectionPlaceRatings.repository.ts | 3 +- .../CollectionPlaces.repository.ts | 12 +- .../db/repositories/Collections.repository.ts | 82 ++---- .../DawarichVisitSuggestions.repository.ts | 24 +- .../DayAccommodations.repository.ts | 58 +--- .../repositories/DayAssignments.repository.ts | 63 +--- .../db/repositories/DayNotes.repository.ts | 7 +- server/src/db/repositories/Days.repository.ts | 10 +- .../DocumentConnections.repository.ts | 7 +- .../DocumentSyncItems.repository.ts | 51 +--- .../db/repositories/FileLinks.repository.ts | 29 +- .../repositories/GoogleApiUsage.repository.ts | 5 +- .../HiddenCountries.repository.ts | 5 +- .../repositories/HiddenRegions.repository.ts | 5 +- .../JourneyContributors.repository.ts | 8 +- .../repositories/JourneyEntries.repository.ts | 52 +--- .../JourneyEntryPhotos.repository.ts | 24 +- .../repositories/JourneyPhotos.repository.ts | 33 +-- .../repositories/JourneyTrips.repository.ts | 17 +- .../db/repositories/Journeys.repository.ts | 35 +-- .../repositories/Notifications.repository.ts | 8 +- .../db/repositories/OauthTokens.repository.ts | 15 +- .../db/repositories/PackingBags.repository.ts | 23 +- .../PackingCategoryAssignees.repository.ts | 12 +- .../PackingItemContributors.repository.ts | 6 +- .../repositories/PackingItems.repository.ts | 19 +- .../PackingTemplateCategories.repository.ts | 13 +- .../PackingTemplateItems.repository.ts | 14 +- .../PackingTemplates.repository.ts | 14 +- .../src/db/repositories/Photos.repository.ts | 7 +- .../repositories/PlaceRatings.repository.ts | 3 +- .../repositories/PlaceRegions.repository.ts | 8 +- .../src/db/repositories/Places.repository.ts | 66 +---- .../PluginCapabilityAudit.repository.ts | 18 +- .../repositories/PluginErrorLog.repository.ts | 7 +- .../PluginOauthState.repository.ts | 11 +- .../PluginOauthTokens.repository.ts | 20 +- .../PluginUserErasureQueue.repository.ts | 8 +- .../PushSubscriptions.repository.ts | 20 +- .../ReservationDayPositions.repository.ts | 24 +- .../ReservationEndpoints.repository.ts | 15 +- .../repositories/Reservations.repository.ts | 208 +++---------- .../RouteUsageDaily.repository.ts | 14 +- .../SchoolHolidayCountries.repository.ts | 5 +- .../db/repositories/ShareTokens.repository.ts | 5 +- server/src/db/repositories/Tags.repository.ts | 20 +- .../TodoCategoryAssignees.repository.ts | 10 +- .../db/repositories/TodoItems.repository.ts | 27 +- .../repositories/TourWaypoints.repository.ts | 9 +- .../src/db/repositories/Tours.repository.ts | 8 +- .../repositories/TripAlbumLinks.repository.ts | 68 ++--- .../db/repositories/TripFiles.repository.ts | 7 +- .../TripInviteTokens.repository.ts | 6 +- .../db/repositories/TripPhotos.repository.ts | 72 ++--- .../src/db/repositories/Trips.repository.ts | 74 +---- .../repositories/VacayEntries.repository.ts | 11 +- .../VacayPlanMembers.repository.ts | 11 +- .../db/repositories/VacayPlans.repository.ts | 5 +- .../db/repositories/VacayShares.repository.ts | 16 +- .../VisitedCountries.repository.ts | 25 +- .../repositories/VisitedRegions.repository.ts | 17 +- .../WebauthnChallenges.repository.ts | 17 +- .../_shared/packing-visibility.ts | 13 +- .../_shared/reservation-travelers-owns.ts | 15 +- .../_shared/reservation-visibility.ts | 29 +- .../tests/unit/db/generate-db-types.test.ts | 166 +++++++++++ .../reservation-travelers-owns.parity.test.ts | 5 +- .../_shared/reservation-visibility.test.ts | 10 +- server/tsconfig.scripts.json | 2 +- sonar-project.properties | 5 +- wiki/Development-environment.md | 2 +- 227 files changed, 3244 insertions(+), 1394 deletions(-) create mode 100644 server/scripts/generate-db-types.ts create mode 100644 server/src/db/kysely/Addons.table.ts create mode 100644 server/src/db/kysely/AppSettings.table.ts create mode 100644 server/src/db/kysely/AssignmentParticipants.table.ts create mode 100644 server/src/db/kysely/AuditLog.table.ts create mode 100644 server/src/db/kysely/BucketList.table.ts create mode 100644 server/src/db/kysely/BudgetCategoryOrder.table.ts create mode 100644 server/src/db/kysely/BudgetItemMembers.table.ts create mode 100644 server/src/db/kysely/BudgetItemPayers.table.ts create mode 100644 server/src/db/kysely/BudgetItems.table.ts create mode 100644 server/src/db/kysely/BudgetSettlements.table.ts create mode 100644 server/src/db/kysely/Categories.table.ts create mode 100644 server/src/db/kysely/CollabLinks.table.ts create mode 100644 server/src/db/kysely/CollabMessageReactions.table.ts create mode 100644 server/src/db/kysely/CollabMessages.table.ts create mode 100644 server/src/db/kysely/CollabNotes.table.ts create mode 100644 server/src/db/kysely/CollabPollVotes.table.ts create mode 100644 server/src/db/kysely/CollabPolls.table.ts create mode 100644 server/src/db/kysely/CollectionLabels.table.ts create mode 100644 server/src/db/kysely/CollectionMembers.table.ts create mode 100644 server/src/db/kysely/CollectionPlaceLabels.table.ts create mode 100644 server/src/db/kysely/CollectionPlaceRatings.table.ts create mode 100644 server/src/db/kysely/CollectionPlaceTags.table.ts create mode 100644 server/src/db/kysely/CollectionPlaces.table.ts create mode 100644 server/src/db/kysely/Collections.table.ts create mode 100644 server/src/db/kysely/DawarichConnections.table.ts create mode 100644 server/src/db/kysely/DawarichVisitSuggestions.table.ts create mode 100644 server/src/db/kysely/DayAccommodations.table.ts create mode 100644 server/src/db/kysely/DayAssignments.table.ts create mode 100644 server/src/db/kysely/DayNotes.table.ts create mode 100644 server/src/db/kysely/Days.table.ts create mode 100644 server/src/db/kysely/DocumentConnections.table.ts create mode 100644 server/src/db/kysely/DocumentProviderFields.table.ts create mode 100644 server/src/db/kysely/DocumentProviders.table.ts create mode 100644 server/src/db/kysely/DocumentSyncItems.table.ts create mode 100644 server/src/db/kysely/FileLinks.table.ts create mode 100644 server/src/db/kysely/GoogleApiUsage.table.ts create mode 100644 server/src/db/kysely/GooglePlacePhotoMeta.table.ts create mode 100644 server/src/db/kysely/HiddenCountries.table.ts create mode 100644 server/src/db/kysely/HiddenRegions.table.ts create mode 100644 server/src/db/kysely/IdempotencyKeys.table.ts create mode 100644 server/src/db/kysely/InviteTokens.table.ts create mode 100644 server/src/db/kysely/JourneyBooks.table.ts create mode 100644 server/src/db/kysely/JourneyContributors.table.ts create mode 100644 server/src/db/kysely/JourneyEntries.table.ts create mode 100644 server/src/db/kysely/JourneyEntryPhotos.table.ts create mode 100644 server/src/db/kysely/JourneyPhotos.table.ts create mode 100644 server/src/db/kysely/JourneyShareTokens.table.ts create mode 100644 server/src/db/kysely/JourneyTrips.table.ts create mode 100644 server/src/db/kysely/Journeys.table.ts create mode 100644 server/src/db/kysely/McpTokens.table.ts create mode 100644 server/src/db/kysely/Migrations.table.ts create mode 100644 server/src/db/kysely/NotificationChannelPreferences.table.ts create mode 100644 server/src/db/kysely/Notifications.table.ts create mode 100644 server/src/db/kysely/OauthClients.table.ts create mode 100644 server/src/db/kysely/OauthConsents.table.ts create mode 100644 server/src/db/kysely/OauthTokens.table.ts create mode 100644 server/src/db/kysely/PackingBagMembers.table.ts create mode 100644 server/src/db/kysely/PackingBags.table.ts create mode 100644 server/src/db/kysely/PackingCategoryAssignees.table.ts create mode 100644 server/src/db/kysely/PackingItemContributors.table.ts create mode 100644 server/src/db/kysely/PackingItemRecipients.table.ts create mode 100644 server/src/db/kysely/PackingItems.table.ts create mode 100644 server/src/db/kysely/PackingTemplateCategories.table.ts create mode 100644 server/src/db/kysely/PackingTemplateItems.table.ts create mode 100644 server/src/db/kysely/PackingTemplates.table.ts create mode 100644 server/src/db/kysely/PasswordResetTokens.table.ts create mode 100644 server/src/db/kysely/PhotoProviderFields.table.ts create mode 100644 server/src/db/kysely/PhotoProviders.table.ts create mode 100644 server/src/db/kysely/Photos.table.ts create mode 100644 server/src/db/kysely/PlaceDetailsCache.table.ts create mode 100644 server/src/db/kysely/PlaceRatings.table.ts create mode 100644 server/src/db/kysely/PlaceRegions.table.ts create mode 100644 server/src/db/kysely/PlaceShadowPicks.table.ts create mode 100644 server/src/db/kysely/PlaceTags.table.ts create mode 100644 server/src/db/kysely/Places.table.ts create mode 100644 server/src/db/kysely/PluginActions.table.ts create mode 100644 server/src/db/kysely/PluginCapabilityAudit.table.ts create mode 100644 server/src/db/kysely/PluginEgressHosts.table.ts create mode 100644 server/src/db/kysely/PluginEntityMetadata.table.ts create mode 100644 server/src/db/kysely/PluginErrorLog.table.ts create mode 100644 server/src/db/kysely/PluginMetaMigrations.table.ts create mode 100644 server/src/db/kysely/PluginOauthState.table.ts create mode 100644 server/src/db/kysely/PluginOauthTokens.table.ts create mode 100644 server/src/db/kysely/PluginScheduledTasks.table.ts create mode 100644 server/src/db/kysely/PluginSettingsFields.table.ts create mode 100644 server/src/db/kysely/PluginUserConfig.table.ts create mode 100644 server/src/db/kysely/PluginUserErasureQueue.table.ts create mode 100644 server/src/db/kysely/Plugins.table.ts create mode 100644 server/src/db/kysely/PushSubscriptions.table.ts create mode 100644 server/src/db/kysely/ReservationDayPositions.table.ts create mode 100644 server/src/db/kysely/ReservationEndpoints.table.ts create mode 100644 server/src/db/kysely/ReservationTravelers.table.ts create mode 100644 server/src/db/kysely/Reservations.table.ts create mode 100644 server/src/db/kysely/RoadtripDayBoundaries.table.ts create mode 100644 server/src/db/kysely/RoadtripDayTracks.table.ts create mode 100644 server/src/db/kysely/RoadtripPreferences.table.ts create mode 100644 server/src/db/kysely/RoadtripVias.table.ts create mode 100644 server/src/db/kysely/RouteUsageDaily.table.ts create mode 100644 server/src/db/kysely/SchemaVersion.table.ts create mode 100644 server/src/db/kysely/SchoolHolidayCountries.table.ts create mode 100644 server/src/db/kysely/SchoolHolidayPeriods.table.ts create mode 100644 server/src/db/kysely/SchoolHolidayRegions.table.ts create mode 100644 server/src/db/kysely/Settings.table.ts create mode 100644 server/src/db/kysely/ShareTokens.table.ts create mode 100644 server/src/db/kysely/Tags.table.ts create mode 100644 server/src/db/kysely/TodoCategoryAssignees.table.ts create mode 100644 server/src/db/kysely/TodoItems.table.ts create mode 100644 server/src/db/kysely/TourTypes.table.ts create mode 100644 server/src/db/kysely/TourWaypoints.table.ts create mode 100644 server/src/db/kysely/Tours.table.ts create mode 100644 server/src/db/kysely/TrekPhotoCacheMeta.table.ts create mode 100644 server/src/db/kysely/TrekPhotos.table.ts create mode 100644 server/src/db/kysely/TripAlbumLinks.table.ts create mode 100644 server/src/db/kysely/TripDocumentLinks.table.ts create mode 100644 server/src/db/kysely/TripFiles.table.ts create mode 100644 server/src/db/kysely/TripInviteTokens.table.ts create mode 100644 server/src/db/kysely/TripMembers.table.ts create mode 100644 server/src/db/kysely/TripPhotos.table.ts create mode 100644 server/src/db/kysely/Trips.table.ts create mode 100644 server/src/db/kysely/UserNoticeDismissals.table.ts create mode 100644 server/src/db/kysely/Users.table.ts create mode 100644 server/src/db/kysely/VacayCompanyHolidays.table.ts create mode 100644 server/src/db/kysely/VacayEntries.table.ts create mode 100644 server/src/db/kysely/VacayHolidayCalendars.table.ts create mode 100644 server/src/db/kysely/VacayPlanMembers.table.ts create mode 100644 server/src/db/kysely/VacayPlans.table.ts create mode 100644 server/src/db/kysely/VacayShares.table.ts create mode 100644 server/src/db/kysely/VacayUserColors.table.ts create mode 100644 server/src/db/kysely/VacayUserSettings.table.ts create mode 100644 server/src/db/kysely/VacayUserYears.table.ts create mode 100644 server/src/db/kysely/VacayYears.table.ts create mode 100644 server/src/db/kysely/VisitedCountries.table.ts create mode 100644 server/src/db/kysely/VisitedRegions.table.ts create mode 100644 server/src/db/kysely/WebauthnChallenges.table.ts create mode 100644 server/src/db/kysely/WebauthnCredentials.table.ts create mode 100644 server/src/db/kysely/columns.ts create mode 100644 server/src/db/kysely/db.ts create mode 100644 server/tests/unit/db/generate-db-types.test.ts diff --git a/CLAUDE.md b/CLAUDE.md index a15100de3..22ca3ef42 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -101,7 +101,7 @@ These principles come out of a full-repo audit and shape all new code: - **Protect the crown jewels.** The client's offline-first data core (repos + mutation queue + Dexie), the out-of-process plugin sandbox, the Zod contract layer, and the auth primitives are production-grade. Extend them; never route around them or rewrite them in anger. - **No "modern shell over legacy core."** The debt pattern is a modern frame delegating to the old approach underneath (on the client: feature components calling the raw API past the offline core). New code goes all-in on the target architecture; when touching a legacy seam, migrate it rather than adding another wrapper. -- **Single source of truth over manual synchronization.** Never add a hand-mirrored copy of state, schema, or contract (server↔Dexie↔Zustand, schema↔SQL, the plugin contract). Derive from one source, or guard the copy with a parity test that cannot silently skip — the server entities are the precedent: `npm run gen:entities`/`check:entities --workspace=server` (`server/scripts/generate-entities.ts`) regenerate them from the live migrated schema instead of hand-editing, and a parity test (PARITY-009) pins entity-vs-DB drift (delete rules, index names) at zero skips. +- **Single source of truth over manual synchronization.** Never add a hand-mirrored copy of state, schema, or contract (server↔Dexie↔Zustand, schema↔SQL, the plugin contract). Derive from one source, or guard the copy with a parity test that cannot silently skip — the server entities are the precedent: `npm run gen:entities`/`check:entities --workspace=server` (`server/scripts/generate-entities.ts`) regenerate them from the live migrated schema instead of hand-editing, and a parity test (PARITY-009) pins entity-vs-DB drift (delete rules, index names) at zero skips. The Kysely table types the repositories query through are generated the same way (`gen:db-types`/`check:db-types`, `server/scripts/generate-db-types.ts`). - **DI over global mutable module state.** New server code injects its dependencies; new client code avoids `window`-global buses and mutable module state. - **Use the runtime's native idioms.** Prefer React 19 features (`useOptimistic`, Actions, `use()`/Suspense) and Nest subsystems (providers, pipes, guards, `@nestjs/schedule`) over hand-rolled equivalents. - **Fail closed, gates stay on.** Security switches default to safe; misconfiguration must refuse, not degrade. Never lower a quality gate to land a change — no new `any`, no new `eslint-disable`, no downgrading rules to `warn`, no lowered coverage thresholds. diff --git a/server/CLAUDE.md b/server/CLAUDE.md index b342b42f0..b313668dd 100644 --- a/server/CLAUDE.md +++ b/server/CLAUDE.md @@ -15,6 +15,8 @@ npm run test # vitest run; also test:unit / test:integration / test npm run test:coverage # istanbul coverage; per-domain ratchet over src/nest/** npm run gen:plugin-facts # regenerate the plugin-protocol tables into plugin-sdk/ + shared/ npm run check:plugin-facts # CI gate — fails if the generated copies drifted +npm run gen:db-types # regenerate the Kysely table types in src/db/kysely/ from the migrated schema +npm run check:db-types # CI gate: fails when src/db/kysely/ no longer matches the migrations node scripts/coverage-thresholds.mjs # after test:coverage — prints the ratchet block for vitest.config.ts npm run db:call-graph -- --sync --tx [--domains nest/days,…] # sync DB-touching methods + transaction sites (exit 1 if any) npm run lint:size # no file in src/ or scripts/ past 1000 lines, longer ones only shrink (CI gate) @@ -42,7 +44,7 @@ Nest owns everything. Every domain is a DI module under `src/nest//` (`c - **Scheduling**: `src/nest/scheduling/` (`CronRegistrarService`) is the one way to schedule a cron. Jobs are `*.job.ts` providers in their owning domain. The registrar refuses to schedule under `NODE_ENV=test` (an integration test pins it). **Never use a `@Cron` decorator** — it bypasses that gate. - **Plugins** (`src/nest/plugins/`): the child-process runtime (`supervisor/`, `runtime/plugin-host-entry.ts`, `protocol/envelope.ts`) is **intentionally not Nest** — it is the security boundary. `host/rpc-host.ts` registers an RPC method at spawn only if the plugin holds the unlocking permission (registration = authorization). Install-time gates live in `install/`; the manifest's `trek` version range fails closed, and `TREK_PLUGINS_IGNORE_TREK_RANGE` downgrades that to a warning. The protocol tables in `protocol/envelope.ts` (+ `src/plugin-event-sink.ts`) are **generated** into `plugin-sdk/` and `shared/` — run `gen:plugin-facts` after touching them and commit the output. `runtime/egress-policy.ts` is a hand-kept mirror guarded by a parity test in `plugin-sdk/`; change both sides together. - **Storage**: `src/nest/storage/` is the upload driver abstraction (local / S3 / mirror behind one interface, with an admin surface and a usage job). Domain services never touch the filesystem or the S3 SDK directly. -- **DB** (`src/db/`): `better-sqlite3`, WAL, FK on. `database.ts` only holds the connection and applies pragmas. It does not build a schema, and importing it opens nothing (the first reader does). The connection's lifecycle belongs to the `DatabaseLifecycle` provider (`nest/database/database-lifecycle.service.ts`): `buildApp()` opens it through `open()` (which binds the ORM to later swaps and runs the schema bootstrap below), the shutdown closes it through `close()`, and a restore or the demo reset swaps the file only through the database backup port, `DATABASE_BACKUP` (`nest/database/database-backup.interface.ts`; the SQLite implementation is `nest/backup/sqlite-database-backup.ts`: `VACUUM INTO` snapshot, close, atomic file swap, `reopen()`). The port works on `DatabaseLifecycle.file`, the one resolved path (`TREK_DB_FILE` or `data/travel.db`), and a snapshot that fails fails the backup rather than archiving the live file. `MaintenanceRepository` is provided only by `MaintenanceModule`'s factory and injected everywhere else; no consumer constructs it. A provider that has to follow every reopen (the demo reset job saves the first demo baseline after a restore's re-bootstrap seeded the example trips) registers with `DatabaseLifecycle.onReopened()`, which runs after the reopen's schema bootstrap; a listener contains its own failures, since one that throws fails the reopen. MikroORM's migrations (`db/migrations/`) are the only schema source, **including for tests**: the hand-kept `schema.ts`/`migrations.ts`/`seeds.ts` builders and the parity test that guarded them are gone. Seeding is the MikroORM seeders in `db/seeders/`, applied by `db/orm.ts` from `buildApp()` before anything reads. An install the retired positional runner migrated (a `schema_version` row, no `mikro_orm_migrations` rows) is baselined by `db/legacy-baseline.ts`: the migrations whose `Legacy migration step N` docstring is ≤ its version are recorded as executed (never replayed) in the same transaction as the migrator run, while the baseline migration itself still runs first, as the legacy runner's `createTables()` did on every boot; anything it cannot map refuses the boot. Before a boot applies pending migrations to a file database that holds anything, `db/pre-migrate-snapshot.ts` writes a `VACUUM INTO` copy next to it (`pre-migrate--