Commit Graph

15 Commits

Author SHA1 Message Date
Maurice ebd8a4f8c9 build(server): lint:boundaries counts the RPC and MCP layers as domains and sees getRepository calls
src/nest-rpc, src/nest-mcp and src/mcp import domains and are imported by them, but the domain map only knew src/nest, so their edges dropped out of domainCycles and their repository injections out of foreignRepositories. Each layer now counts as one domain. The repository rule reads the syntax tree for @InjectRepository(X) and for getRepository(X) on an EntityManager, so a comment no longer counts and a foreign read through the EntityManager no longer passes. The baseline takes the cycles and the repository reaches the wider view finds; settings -> Users goes, it was a comment.
2026-10-10 20:16:13 +02:00
Maurice 0f6ae8b928 refactor(vacay): the invite and share tools ask a kernel user lookup instead of injecting UsersRepository
VacayMcp read the caller's username and email straight from UsersRepository, a table the auth domain owns. UserLookupService in auth-core answers exactly that, so vacay neither imports AuthModule nor injects a foreign repository, and its foreignRepositories entry goes.
2026-10-10 20:16:13 +02:00
Maurice a28044dbd4 chore(server): lint:boundaries holds the user-connection repositories and the journey read at their new count
The module comment no longer spells an @InjectRepository call the scanner took
for a foreign Users injection in nest/database, and journey's Users entry is
gone now that it reads the Immich flag through UserImmichRepository.
2026-10-10 20:16:04 +02:00
Maurice 1389fe6984 refactor(place-import): file and shared-list readers move into their own domain over one gpx and one kml codec 2026-10-10 20:16:03 +02:00
Maurice dc42fe9a5a chore(server): lint:boundaries refuses a provider that imports the orchestrator above it 2026-10-10 20:16:02 +02:00
Maurice 3618a4ab9f refactor(maps): the searchText field mask lives beside the Google places provider 2026-10-10 20:16:01 +02:00
Maurice cd0c27921c build(server): lint:boundaries holds foreign repository injections to a baseline
A domain injecting the repository of a table another domain owns couples
the two below the service layer, and nothing counted it. The new
foreignRepositories rule reads every @InjectRepository under src/nest,
looks the entity up in scripts/repository-owners.json (an injected entity
without an owner stops the run) and holds each domain/entity pair to the
baseline, which only shrinks: 209 pairs today.
2026-10-10 20:16:00 +02:00
Maurice 734cbc2a94 refactor(vacay): the invite and share tools read the caller's name from UsersRepository
VacayMcp injected AuthService only to call getCurrentUser for the caller's
username and email before sending an invite or sharing the calendar, which
kept VacayModule importing AuthModule. UsersRepository.findUsernameEmail
answers the same two fields (and undefined for an unknown id, which the
tools already refuse as 'User not found.').
2026-10-10 20:16:00 +02:00
Maurice 806f3c8e62 refactor(addons): the transit-provider setting and photo-provider routes move into the shared kernel
AddonsService read the transit backend through transit/transit-provider.ts
and built photo-provider endpoint paths with memories.helpers, so the addons
domain, which nearly every domain imports for its gates, depended on
transit and memories. Both are free functions over a repository or plain
strings; they move unchanged to common/, where the transit and admin sides
read them too.
2026-10-10 20:15:59 +02:00
Maurice 846d8d4952 refactor(realtime): the gateway asks a journey-access port instead of importing the journey domain
The websocket gateway injected JourneyDomainService to decide who may join
a journey's book room, so the realtime domain, which nearly every domain
imports for its broadcasts, depended on journey and closed a cycle through
all of them. It now injects a JOURNEY_ACCESS port declared in realtime;
JourneyAccessModule (global, imported by AppModule beside the gateway
module) binds it to the same JourneyDomainService method.
2026-10-10 20:15:59 +02:00
Maurice 0c2226c5f0 refactor(realtime): the websocket welcome frame reads the running version from app-config
The gateway imported hostVersion from the plugin install code to put the
version in its welcome frame, which made the realtime domain, imported by
nearly every other, depend on plugins. The running version (image VERSION
or APP_VERSION, else package.json) is app config; runningVersion() holds it
and the plugin host-compat checks call the same function.
2026-10-10 20:15:59 +02:00
Maurice 01fd4e3739 refactor(admin): the admin routes other domains serve keep their DTOs in those domains
NotificationsController, SettingsController, OidcController and the packing
template controller each imported their body DTO from admin/admin.dto.ts,
and AdminController imported the same four without using them. Those
imports tied the notifications, settings, packing and oidc domains to the
admin domain and through it to everything admin depends on. The classes
move unchanged (same names, same @trek/shared schemas) into each domain's
own dto file.
2026-10-10 20:15:59 +02:00
Maurice e40bc71e9f refactor(plugins): the plugin RPC kit moves out of the plugins domain into src/nest-rpc
Every domain's *.rpc.ts was written against rpc-kit, rpc-params, rpc-errors
and PluginGuards, and every domain module imported PluginGuardsModule, all
of it inside src/nest/plugins, while PluginsRuntimeModule imports those same
domains so their handlers exist at boot. That made the plugins domain part
of every cycle. The kit imports no domain but the protocol tables and
permissions/addons for the guards, so it moves to src/nest-rpc beside
src/nest-mcp, with its tests, its README and its extraction rule; the
runtime module keeps its domain imports, which the boot-time coverage check
of the wire surface needs in any subset app.
2026-10-10 20:15:58 +02:00
Maurice cc79f561e5 refactor(auth): guards, auth decorators and ephemeral tokens move into an auth-core kernel
JwtAuthGuard, OptionalJwtAuthGuard, CookieAuthGuard, AdminGuard, the global
and MFA guards, @CurrentUser, @Public, JWT verification and the ephemeral
token service lived in the auth domain, so every controller that checked a
session depended on the whole account module and its imports. They import
no domain themselves; under src/nest/auth-core they are shared kernel like
common/, every importer points there directly, and AtlasModule and
NotificationsModule stop importing AuthModule, which they only did for the
demo gate. lint:boundaries counts auth-core as kernel: 57 fewer cyclic
domain edges, the largest cycle shrinks from 46 to 40 domains.
2026-10-10 20:15:58 +02:00
Maurice 22b398ad8c ci(server): gate import cycles and cross-domain reach-ins with a baseline
Module boundaries were held by review alone. storage.module.ts documents
a cycle that only surfaced at runtime as "imports[1] is undefined", three
modules exist just to break cycles, and nothing stopped the next feature
from reaching into another domain's helpers.

scripts/import-boundaries.mjs parses every import under src/ with the
TypeScript parser and checks five rules against a baseline of today's
violations: load-time file cycles (none today once type-only and lazy
imports and the two-way MikroORM entity relations are left out), new
dependencies between domains that already depend on each other (262
pairs, one tangle around plugins and auth), shared-kernel files importing
a domain (8), imports of another domain's internals (69) and src/db
importing src/nest (5). A domain's public surface is what the code
already treats that way: modules, services, guards, decorators, types,
constants, the audit logger, the plugin RPC kit and the addon gates.

New violations fail, --update only drops entries, and an unreadable
baseline, a missing src/ or an import it cannot resolve stops the run.
2026-10-08 13:02:59 +02:00