Skip to main content
Trang này trả lời bốn câu hỏi:
  1. Tài khoản nhận quyền từ đâu?
  2. Server kiểm tra quyền nào khi mở màn hình hoặc gửi thao tác?
  3. Tài khoản được làm việc với tòa nhà nào?
  4. Code ngăn truy cập chéo tòa nhà ở đâu?

Kết luận hiện tại

Multi-tenant isolation hiện được thực thi bởi application code và quan hệ database. Không tìm thấy PostgreSQL Row-Level Security trong current source code.

Mô hình gán quyền và tòa nhà

Vì PermissionGroups và UserPermissionGroups không có tower_id, source hiện áp dụng cùng một tập quyền cho tất cả tòa nhà trong allowedTowerIds của user.

Quyền được resolve như thế nào?

Server không dùng role, permission hoặc tower claim trong JWT làm nguồn cuối cùng. Mỗi authenticated request đọc lại account và grouped authorization từ database. Test hiện có xác nhận role/tower claim bị sửa trong token không nâng được quyền.

Quy tắc hợp nhất

  • Permission từ nhiều group được hợp nhất theo phép union và loại trùng.
  • Không tìm thấy explicit deny hoặc thứ tự ưu tiên giữa các group.
  • menuPermissions chỉ gồm permission có has_menu truthy và identifier bắt đầu bằng /admin.
  • Menu visibility và server authorization là hai kết quả riêng.
  • Operator phải có authorization_source = grouped.
  • AuthUsers.permissions và AuthUsers.allowed_tower_ids vẫn tồn tại trong schema, nhưng grouped resolution đọc quyền/tower từ các bảng quan hệ.

Ba loại permission

canPerformAction() chấp nhận permission * như wildcard cho action. canAccessRoute() chỉ kiểm tra exact route path và không xử lý * như route wildcard.

Route, menu và mutation

Nhìn thấy menu không chứng minh mutation được phép. Handler kiểm tra lại route và action/CRUD permission khi nhận request.

Specialized workflow actions

Permission contract của manage_feedback_forms đang không đồng bộ. app/admin/[[...slug]]/page.tsx và src/lib/admin-route-policy.ts kiểm tra action:manage_feedback_forms, nhưng identifier này không có trong ACTION_PERMISSION_NAMES hoặc stable permission catalog. Vì savePermissionGroup() chỉ nhận identifier thuộc stable catalog, current group editor không thể thêm action này vào một group mới. super-admin vẫn vượt qua action check.

Tenant scope theo tòa nhà

Cách active tower được chọn

  1. Grouped authorization chỉ lấy các tower có status active qua UserBuildings.
  2. Khi tạo session, server giữ tower được yêu cầu nếu tower đó còn trong allowedTowerIds.
  3. Nếu không còn hợp lệ, server chọn phần tử đầu tiên của allowedTowerIds; nếu danh sách rỗng thì dùng chuỗi rỗng.
  4. POST /auth/switch-tower chỉ tạo session mới khi tower đích nằm trong allowedTowerIds.

Enforcement path cho dữ liệu quản trị

Các domain service tài chính, resident, vehicle, reminder và import nhận towerId từ handler và tự thêm điều kiện tower vào query/mutation. Schema còn dùng composite relation có tower_id cho nhiều quan hệ resident, apartment, vehicle, bill và import để ngăn liên kết chéo tower ở database level.

Quản trị RBAC

Permission group là global trong schema. actorTowerId khi lưu group chỉ được dùng trong audit log; source không scope group theo tower.

super-admin

super-admin bypass các hàm kiểm tra route, workflow action và CRUD action. Bypass này không tự mở rộng activeTowerId: session vẫn lấy allowedTowerIds từ UserBuildings, và switch tower vẫn yêu cầu tower đích nằm trong danh sách đó.
Source hiện có một khác biệt trong workflow gán tower. createPortalUser() cho phép super-admin bỏ qua actor tower scope. saveUserRbacAssignments() nhận actorIsSuperAdmin, nhưng bước kiểm tra tower mới vẫn yêu cầu mọi tower nằm trong actorTowerCodes. Trong khi đó, dữ liệu UI cho super-admin liệt kê tất cả active towers. Tài liệu ghi nhận khác biệt này và không tự diễn giải behavior dự kiến.

Acceptance Criteria hiện tại

53 admin route policies nằm trong Route catalog. Xem Vai trò và phạm vi cho cách người vận hành hiểu quyền; xem Kiến trúc thực thi cho enforcement path dành cho developer.