From 0b9a9f311e68ce09fbcbb83f4f3fa8f66f3a2724 Mon Sep 17 00:00:00 2001 From: Myx Date: Sat, 11 Apr 2026 13:25:26 +0200 Subject: [PATCH] refactor: stricter domain: access-control --- toju-app/src/app/domains/README.md | 2 +- .../src/app/domains/access-control/README.md | 21 ++++++++++++------- .../domain/access-control.logic.ts | 6 ------ .../access-control.constants.ts | 2 +- .../access-control.model.ts} | 2 +- .../access-control/domain/rules/ban.rules.ts} | 2 +- .../domain/{ => rules}/permission.rules.ts | 8 +++---- .../{ => rules}/role-assignment.rules.ts | 8 +++---- .../domain/{ => rules}/role.rules.ts | 6 +++--- .../domain/{ => rules}/room.rules.ts | 8 +++---- .../access-control.util.ts} | 4 ++-- .../src/app/domains/access-control/index.ts | 13 ++++++------ .../server-search/server-search.component.ts | 2 +- .../servers/servers-rail.component.ts | 2 +- .../store/rooms/room-state-sync.effects.ts | 2 +- toju-app/src/app/store/rooms/rooms.effects.ts | 2 +- 16 files changed, 46 insertions(+), 44 deletions(-) delete mode 100644 toju-app/src/app/domains/access-control/domain/access-control.logic.ts rename toju-app/src/app/domains/access-control/domain/{ => constants}/access-control.constants.ts (94%) rename toju-app/src/app/domains/access-control/domain/{access-control.models.ts => models/access-control.model.ts} (89%) rename toju-app/src/app/{core/helpers/room-ban.helpers.ts => domains/access-control/domain/rules/ban.rules.ts} (96%) rename toju-app/src/app/domains/access-control/domain/{ => rules}/permission.rules.ts (97%) rename toju-app/src/app/domains/access-control/domain/{ => rules}/role-assignment.rules.ts (96%) rename toju-app/src/app/domains/access-control/domain/{ => rules}/role.rules.ts (97%) rename toju-app/src/app/domains/access-control/domain/{ => rules}/room.rules.ts (97%) rename toju-app/src/app/domains/access-control/domain/{access-control.internal.ts => util/access-control.util.ts} (97%) diff --git a/toju-app/src/app/domains/README.md b/toju-app/src/app/domains/README.md index e58b65b..caca01e 100644 --- a/toju-app/src/app/domains/README.md +++ b/toju-app/src/app/domains/README.md @@ -9,7 +9,7 @@ infrastructure adapters and UI. | Domain | Purpose | Public entry point | | -------------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------- | | **attachment** | File upload/download, chunk transfer, persistence | `AttachmentFacade` | -| **access-control** | Role, permission, moderation, and room access rules | `normalizeRoomAccessControl()`, `resolveRoomPermission()` | +| **access-control** | Role, permission, ban matching, moderation, and room access rules | `normalizeRoomAccessControl()`, `resolveRoomPermission()`, `hasRoomBanForUser()` | | **auth** | Login / register HTTP orchestration, user-bar UI | `AuthService` | | **chat** | Messaging rules, sync logic, GIF/Klipy integration, chat UI | `KlipyService`, `canEditMessage()`, `ChatMessagesComponent` | | **notifications** | Notification preferences, unread tracking, desktop alert orchestration | `NotificationsFacade` | diff --git a/toju-app/src/app/domains/access-control/README.md b/toju-app/src/app/domains/access-control/README.md index 27c126f..82e3d5d 100644 --- a/toju-app/src/app/domains/access-control/README.md +++ b/toju-app/src/app/domains/access-control/README.md @@ -7,13 +7,18 @@ Role and permission rules for servers, including default system roles, role assi ``` access-control/ ├── domain/ -│ ├── access-control.models.ts MemberIdentity and RoomPermissionDefinition domain types -│ ├── access-control.constants.ts SYSTEM_ROLE_IDS and permission metadata -│ ├── role.rules.ts Role defaults, normalization, ordering, create/update helpers -│ ├── role-assignment.rules.ts Assignment normalization and member-role lookups -│ ├── permission.rules.ts Permission resolution and moderation hierarchy checks -│ ├── room.rules.ts Legacy compatibility, room hydration, room-level normalization -│ └── access-control.logic.ts Public barrel for domain rules +│ ├── models/ +│ │ └── access-control.model.ts MemberIdentity and RoomPermissionDefinition domain types +│ ├── constants/ +│ │ └── access-control.constants.ts SYSTEM_ROLE_IDS and permission metadata +│ ├── util/ +│ │ └── access-control.util.ts Internal helpers (normalization, identity matching, sorting) +│ └── rules/ +│ ├── role.rules.ts Role defaults, normalization, ordering, create/update helpers +│ ├── role-assignment.rules.ts Assignment normalization and member-role lookups +│ ├── permission.rules.ts Permission resolution and moderation hierarchy checks +│ ├── room.rules.ts Legacy compatibility, room hydration, room-level normalization +│ └── ban.rules.ts Ban matching and user-ban resolution │ └── index.ts Domain barrel used by other layers ``` @@ -29,6 +34,8 @@ access-control/ | `canManageMember(...)` | Applies both permission checks and role hierarchy checks | | `canManageRole(...)` | Prevents editing roles at or above the actor's highest role | | `normalizeRoomAccessControl(room)` | Produces a fully hydrated room with normalized roles, assignments, overrides, and legacy compatibility fields | +| `hasRoomBanForUser(bans, user, persistedUserId?)` | Returns true when any active ban entry targets the provided user | +| `isRoomBanMatch(ban, user, persistedUserId?)` | Returns true when a single ban entry targets the provided user | ## Layering diff --git a/toju-app/src/app/domains/access-control/domain/access-control.logic.ts b/toju-app/src/app/domains/access-control/domain/access-control.logic.ts deleted file mode 100644 index 78fa2ca..0000000 --- a/toju-app/src/app/domains/access-control/domain/access-control.logic.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './access-control.models'; -export * from './access-control.constants'; -export * from './role.rules'; -export * from './role-assignment.rules'; -export * from './permission.rules'; -export * from './room.rules'; diff --git a/toju-app/src/app/domains/access-control/domain/access-control.constants.ts b/toju-app/src/app/domains/access-control/domain/constants/access-control.constants.ts similarity index 94% rename from toju-app/src/app/domains/access-control/domain/access-control.constants.ts rename to toju-app/src/app/domains/access-control/domain/constants/access-control.constants.ts index 476a8ef..f517a16 100644 --- a/toju-app/src/app/domains/access-control/domain/access-control.constants.ts +++ b/toju-app/src/app/domains/access-control/domain/constants/access-control.constants.ts @@ -1,4 +1,4 @@ -import type { RoomPermissionDefinition } from './access-control.models'; +import type { RoomPermissionDefinition } from '../models/access-control.model'; export const SYSTEM_ROLE_IDS = { everyone: 'system-everyone', diff --git a/toju-app/src/app/domains/access-control/domain/access-control.models.ts b/toju-app/src/app/domains/access-control/domain/models/access-control.model.ts similarity index 89% rename from toju-app/src/app/domains/access-control/domain/access-control.models.ts rename to toju-app/src/app/domains/access-control/domain/models/access-control.model.ts index eed4940..a126e2a 100644 --- a/toju-app/src/app/domains/access-control/domain/access-control.models.ts +++ b/toju-app/src/app/domains/access-control/domain/models/access-control.model.ts @@ -2,7 +2,7 @@ import type { RoomMember, RoomPermissionKey, User -} from '../../../shared-kernel'; +} from '../../../../shared-kernel'; export interface RoomPermissionDefinition { key: RoomPermissionKey; diff --git a/toju-app/src/app/core/helpers/room-ban.helpers.ts b/toju-app/src/app/domains/access-control/domain/rules/ban.rules.ts similarity index 96% rename from toju-app/src/app/core/helpers/room-ban.helpers.ts rename to toju-app/src/app/domains/access-control/domain/rules/ban.rules.ts index 49fe496..187a06b 100644 --- a/toju-app/src/app/core/helpers/room-ban.helpers.ts +++ b/toju-app/src/app/domains/access-control/domain/rules/ban.rules.ts @@ -1,4 +1,4 @@ -import { BanEntry, User } from '../models/index'; +import { BanEntry, User } from '../../../../shared-kernel'; type BanAwareUser = Pick | null | undefined; diff --git a/toju-app/src/app/domains/access-control/domain/permission.rules.ts b/toju-app/src/app/domains/access-control/domain/rules/permission.rules.ts similarity index 97% rename from toju-app/src/app/domains/access-control/domain/permission.rules.ts rename to toju-app/src/app/domains/access-control/domain/rules/permission.rules.ts index 75bcd7c..e3dfef9 100644 --- a/toju-app/src/app/domains/access-control/domain/permission.rules.ts +++ b/toju-app/src/app/domains/access-control/domain/rules/permission.rules.ts @@ -4,9 +4,9 @@ import { Room, RoomPermissionKey, RoomRole -} from '../../../shared-kernel'; -import { SYSTEM_ROLE_IDS } from './access-control.constants'; -import type { MemberIdentity } from './access-control.models'; +} from '../../../../shared-kernel'; +import { SYSTEM_ROLE_IDS } from '../constants/access-control.constants'; +import type { MemberIdentity } from '../models/access-control.model'; import { buildRoleLookup, getRolePermissionState, @@ -14,7 +14,7 @@ import { normalizePermissionState, roleSortAscending, compareText -} from './access-control.internal'; +} from '../util/access-control.util'; import { getAssignedRoleIds, getHighestAssignedRole } from './role-assignment.rules'; import { getRoomRoleById, normalizeRoomRoles } from './role.rules'; diff --git a/toju-app/src/app/domains/access-control/domain/role-assignment.rules.ts b/toju-app/src/app/domains/access-control/domain/rules/role-assignment.rules.ts similarity index 96% rename from toju-app/src/app/domains/access-control/domain/role-assignment.rules.ts rename to toju-app/src/app/domains/access-control/domain/rules/role-assignment.rules.ts index 0236cf6..2310f22 100644 --- a/toju-app/src/app/domains/access-control/domain/role-assignment.rules.ts +++ b/toju-app/src/app/domains/access-control/domain/rules/role-assignment.rules.ts @@ -3,9 +3,9 @@ import { RoomMember, RoomRole, RoomRoleAssignment -} from '../../../shared-kernel'; -import { SYSTEM_ROLE_IDS } from './access-control.constants'; -import type { MemberIdentity } from './access-control.models'; +} from '../../../../shared-kernel'; +import { SYSTEM_ROLE_IDS } from '../constants/access-control.constants'; +import type { MemberIdentity } from '../models/access-control.model'; import { buildRoleLookup, compareText, @@ -13,7 +13,7 @@ import { matchesIdentity, roleSortDescending, uniqueStrings -} from './access-control.internal'; +} from '../util/access-control.util'; import { getRoomRoleById, normalizeRoomRoles } from './role.rules'; function sortAssignments(assignments: readonly RoomRoleAssignment[]): RoomRoleAssignment[] { diff --git a/toju-app/src/app/domains/access-control/domain/role.rules.ts b/toju-app/src/app/domains/access-control/domain/rules/role.rules.ts similarity index 97% rename from toju-app/src/app/domains/access-control/domain/role.rules.ts rename to toju-app/src/app/domains/access-control/domain/rules/role.rules.ts index 46f9ee3..6d7c2af 100644 --- a/toju-app/src/app/domains/access-control/domain/role.rules.ts +++ b/toju-app/src/app/domains/access-control/domain/rules/role.rules.ts @@ -2,8 +2,8 @@ import { RoomPermissionMatrix, RoomPermissions, RoomRole -} from '../../../shared-kernel'; -import { SYSTEM_ROLE_IDS } from './access-control.constants'; +} from '../../../../shared-kernel'; +import { SYSTEM_ROLE_IDS } from '../constants/access-control.constants'; import { buildRoleLookup, buildSystemRole, @@ -12,7 +12,7 @@ import { normalizePermissionMatrix, roleSortAscending, roleSortDescending -} from './access-control.internal'; +} from '../util/access-control.util'; const ROLE_COLORS = { everyone: '#6b7280', diff --git a/toju-app/src/app/domains/access-control/domain/room.rules.ts b/toju-app/src/app/domains/access-control/domain/rules/room.rules.ts similarity index 97% rename from toju-app/src/app/domains/access-control/domain/room.rules.ts rename to toju-app/src/app/domains/access-control/domain/rules/room.rules.ts index 9e378dd..72bf028 100644 --- a/toju-app/src/app/domains/access-control/domain/room.rules.ts +++ b/toju-app/src/app/domains/access-control/domain/rules/room.rules.ts @@ -7,14 +7,14 @@ import { RoomRole, RoomRoleAssignment, UserRole -} from '../../../shared-kernel'; -import { SYSTEM_ROLE_IDS } from './access-control.constants'; +} from '../../../../shared-kernel'; +import { SYSTEM_ROLE_IDS } from '../constants/access-control.constants'; import { getRolePermissionState, permissionStateToBoolean, resolveLegacyAllowState -} from './access-control.internal'; -import type { MemberIdentity } from './access-control.models'; +} from '../util/access-control.util'; +import type { MemberIdentity } from '../models/access-control.model'; import { getAssignedRoleIds, normalizeRoomRoleAssignments, diff --git a/toju-app/src/app/domains/access-control/domain/access-control.internal.ts b/toju-app/src/app/domains/access-control/domain/util/access-control.util.ts similarity index 97% rename from toju-app/src/app/domains/access-control/domain/access-control.internal.ts rename to toju-app/src/app/domains/access-control/domain/util/access-control.util.ts index 8a8163a..6231f0a 100644 --- a/toju-app/src/app/domains/access-control/domain/access-control.internal.ts +++ b/toju-app/src/app/domains/access-control/domain/util/access-control.util.ts @@ -5,8 +5,8 @@ import { RoomRole, RoomRoleAssignment, ROOM_PERMISSION_KEYS -} from '../../../shared-kernel'; -import type { MemberIdentity } from './access-control.models'; +} from '../../../../shared-kernel'; +import type { MemberIdentity } from '../models/access-control.model'; export function normalizeName(name: string): string { return name.trim().replace(/\s+/g, ' '); diff --git a/toju-app/src/app/domains/access-control/index.ts b/toju-app/src/app/domains/access-control/index.ts index 643a68a..a85280d 100644 --- a/toju-app/src/app/domains/access-control/index.ts +++ b/toju-app/src/app/domains/access-control/index.ts @@ -1,6 +1,7 @@ -export * from './domain/access-control.models'; -export * from './domain/access-control.constants'; -export * from './domain/role.rules'; -export * from './domain/role-assignment.rules'; -export * from './domain/permission.rules'; -export * from './domain/room.rules'; +export * from './domain/models/access-control.model'; +export * from './domain/constants/access-control.constants'; +export * from './domain/rules/role.rules'; +export * from './domain/rules/role-assignment.rules'; +export * from './domain/rules/permission.rules'; +export * from './domain/rules/room.rules'; +export * from './domain/rules/ban.rules'; diff --git a/toju-app/src/app/domains/server-directory/feature/server-search/server-search.component.ts b/toju-app/src/app/domains/server-directory/feature/server-search/server-search.component.ts index 8391d10..116f535 100644 --- a/toju-app/src/app/domains/server-directory/feature/server-search/server-search.component.ts +++ b/toju-app/src/app/domains/server-directory/feature/server-search/server-search.component.ts @@ -40,7 +40,7 @@ import { type ServerInfo } from '../../domain/server-directory.models'; import { ServerDirectoryFacade } from '../../application/server-directory.facade'; import { selectCurrentUser } from '../../../../store/users/users.selectors'; import { ConfirmDialogComponent } from '../../../../shared'; -import { hasRoomBanForUser } from '../../../../core/helpers/room-ban.helpers'; +import { hasRoomBanForUser } from '../../../access-control'; @Component({ selector: 'app-server-search', diff --git a/toju-app/src/app/features/servers/servers-rail.component.ts b/toju-app/src/app/features/servers/servers-rail.component.ts index a884861..01856cd 100644 --- a/toju-app/src/app/features/servers/servers-rail.component.ts +++ b/toju-app/src/app/features/servers/servers-rail.component.ts @@ -32,7 +32,7 @@ import { RoomsActions } from '../../store/rooms/rooms.actions'; import { DatabaseService } from '../../infrastructure/persistence'; import { NotificationsFacade } from '../../domains/notifications'; import { type ServerInfo, ServerDirectoryFacade } from '../../domains/server-directory'; -import { hasRoomBanForUser } from '../../core/helpers/room-ban.helpers'; +import { hasRoomBanForUser } from '../../domains/access-control'; import { ConfirmDialogComponent, ContextMenuComponent, diff --git a/toju-app/src/app/store/rooms/room-state-sync.effects.ts b/toju-app/src/app/store/rooms/room-state-sync.effects.ts index 6e59224..7d4912e 100644 --- a/toju-app/src/app/store/rooms/room-state-sync.effects.ts +++ b/toju-app/src/app/store/rooms/room-state-sync.effects.ts @@ -40,7 +40,7 @@ import { VoiceState } from '../../shared-kernel'; import { NotificationAudioService, AppSound } from '../../core/services/notification-audio.service'; -import { hasRoomBanForUser } from '../../core/helpers/room-ban.helpers'; +import { hasRoomBanForUser } from '../../domains/access-control'; import { RECONNECT_SOUND_GRACE_MS } from '../../core/constants'; import { VoiceSessionFacade } from '../../domains/voice-session'; import { diff --git a/toju-app/src/app/store/rooms/rooms.effects.ts b/toju-app/src/app/store/rooms/rooms.effects.ts index f5bb89e..ad17235 100644 --- a/toju-app/src/app/store/rooms/rooms.effects.ts +++ b/toju-app/src/app/store/rooms/rooms.effects.ts @@ -41,7 +41,7 @@ import { saveLastViewedChatToStorage } from '../../infrastructure/persistence'; import { ServerDirectoryFacade } from '../../domains/server-directory'; -import { hasRoomBanForUser } from '../../core/helpers/room-ban.helpers'; +import { hasRoomBanForUser } from '../../domains/access-control'; import { Room } from '../../shared-kernel'; import { removeRoomMember,