Initial commit

This commit is contained in:
Igor Martyniuk
2026-06-25 15:53:49 +03:00
commit 1bb0b7e68a
1517 changed files with 218469 additions and 0 deletions
@@ -0,0 +1,53 @@
# Access Control Module
The Access Control module manages admin accounts, roles, and permissions in the admin app. It is the UI boundary for deciding who can access which admin features.
## Source Map
| Area | Path |
| ------------------------- | ------------------------------------------------------- |
| Frontend module | `apps/admin/src/core/AccessControl/` |
| Frontend routes | `apps/admin/src/core/AccessControl/config/routing.tsx` |
| Frontend translations | `apps/admin/src/core/AccessControl/config/translation/` |
| Backend admin module | `backend/app/base_modules/Admin/` |
| Backend role module | `backend/app/base_modules/Role/` |
| Backend permission module | `backend/app/base_modules/Permission/` |
| Permission loader | `backend/app/services/permission_service.ts` |
## Documentation
| Page | Purpose |
| ------------------------- | ------------------------------------------------------------------------------------- |
| [Frontend](./frontend.md) | Routes, UI structure, data layer, forms, translations, and cache invalidation. |
| [Backend](./backend.md) | Admin, role, and permission API routes, policies, validators, and permission loading. |
## Main Capabilities
- List, search, sort, paginate, create, edit, and delete admin accounts.
- Assign roles to admin accounts.
- List, create, edit, and delete roles.
- Assign permissions to roles.
- Load available permission definitions from backend module permission configs.
- Gate access to screens and actions through the Permission core module.
## Ownership Rules
- AccessControl owns management UI for admins, roles, and role permissions.
- Backend Admin owns account persistence and profile update endpoint.
- Backend Role owns role persistence and role-permission sync.
- Backend Permission owns the available permission list endpoint.
- Permission core module owns permission checking and React gates.
- Auth core module owns the current authenticated admin and session state.
## Common Change Guide
| Change | Start Here |
| --------------------------- | ---------------------------------------------------------------------------------------------------- |
| Add an admin field | `entities/AdminEntity.ts`, `data/api/dto.ts`, `data/mappers/AdminMapper.ts`, `view/forms/AdminForm/` |
| Change admin list columns | `view/widgets/AdminTable.tsx` |
| Change role form behavior | `view/forms/RoleForm/` |
| Add a new permission source | Backend module `config/permissions.ts` and `backend/app/services/permission_service.ts` |
| Change cache invalidation | `data/queries/cache.ts` |
| Change translations | `config/translation/en.json` and `config/translation/uk.json` |
| Change backend admin API | `backend/app/base_modules/Admin/controller/admin_controller.ts` |
| Change backend role API | `backend/app/base_modules/Role/controller/role_controller.ts` |
@@ -0,0 +1,89 @@
# Access Control Backend
Access Control frontend uses three backend base modules:
```txt
backend/app/base_modules/Admin/
backend/app/base_modules/Role/
backend/app/base_modules/Permission/
```
## Routes
| Method | Route | Backend | Purpose |
| -------- | ----------------------- | ---------- | ------------------------------------------- |
| `GET` | `/admin` | Admin | Paginated admin list. |
| `GET` | `/admin/:id` | Admin | Admin details with roles. |
| `POST` | `/admin` | Admin | Create admin and sync roles. |
| `PUT` | `/admin/:id` | Admin | Update admin and sync roles. |
| `DELETE` | `/admin/:id` | Admin | Delete admin. |
| `PUT` | `/admin/update-profile` | Admin | Update current authenticated admin profile. |
| `GET` | `/role` | Role | Paginated role list. |
| `GET` | `/role/:id` | Role | Role details with permissions. |
| `POST` | `/role` | Role | Create role and role-permission rows. |
| `PUT` | `/role/:id` | Role | Update role and role-permission rows. |
| `DELETE` | `/role/:id` | Role | Delete role. |
| `GET` | `/permission` | Permission | List all available permission definitions. |
All routes use `middleware.auth()` except login routes owned by Auth.
## Authorization
Policies:
```txt
backend/app/base_modules/Admin/policy/admin_policy.ts
backend/app/base_modules/Role/policy/role_policy.ts
backend/app/base_modules/Permission/policy/permission_policy.ts
```
Permission slugs are defined in:
```txt
backend/app/base_modules/Admin/config/permissions.ts
backend/app/base_modules/Role/config/permissions.ts
```
Current AccessControl slugs:
```txt
admins.view
admins.create
admins.update
admins.delete
role.view
role.create
role.update
role.delete
```
## Permission Loading
Available permissions are collected by:
```txt
backend/app/services/permission_service.ts
```
`getAllPermissions()` scans `app/base_modules/*/config/permissions.ts` and `app/modules/*/config/permissions.ts`. Add permissions to the owning backend module config; do not hard-code them in the frontend.
## Validation
Validators:
```txt
backend/app/base_modules/Admin/validators/admin_create_validator.ts
backend/app/base_modules/Admin/validators/admin_update_validator.ts
backend/app/base_modules/Admin/validators/admin_update_profile_validator.ts
backend/app/base_modules/Role/validator/role_create_validator.ts
backend/app/base_modules/Role/validator/role_update_validator.ts
```
Keep frontend form rules compatible with backend validators. Backend validation is authoritative.
## Data Notes
- Admin create/update syncs assigned roles through the admin-role relation.
- Role create/update rewrites `role_permissions` rows for the role.
- Permission records returned by `/permission` are loaded from permission config files, not only database rows.
- Deleting the final admin is blocked by the Admin controller.
@@ -0,0 +1,145 @@
# Access Control Frontend
The frontend module provides the admin-facing UI for managing admins, roles, and permissions.
Source root:
```txt
apps/admin/src/core/AccessControl/
```
## Directory Structure
```txt
AccessControl/
config/ Routes, menu, messages, translations.
data/
api/ Raw HTTP calls and DTOs.
mappers/ DTO-to-entity mapping.
queries/ React Query hooks, keys, and cache invalidation.
entities/ Admin, role, permission entities and enums.
pages/ Route-level pages.
view/
forms/ Admin and role forms.
layouts/ Module layout.
widgets/ Tables and modal triggers.
```
## Routes
Frontend route config:
```txt
config/routing.tsx
```
Mounted module path:
```txt
/access-control
```
| Route | Page | Purpose |
| ----------------------- | --------------- | ----------------------------------------- |
| `/access-control/admin` | `AdminListPage` | Manage admin accounts and assigned roles. |
| `/access-control/role` | `RoleListPage` | Manage roles and assigned permissions. |
## Data Layer
Raw API calls live in:
```txt
data/api/AdminAPI.ts
data/api/RoleAPI.ts
data/api/PermissionAPI.ts
data/api/dto.ts
```
Query hooks live in:
```txt
data/queries/admin.ts
data/queries/role.ts
data/queries/permission.ts
```
Cache invalidation helpers live in:
```txt
data/queries/cache.ts
```
Current helpers:
```ts
invalidateAdminList();
invalidateAdminDetailed(id?);
invalidateRoleList();
invalidateRoleDetailed(id?);
invalidatePermissionList();
```
## DTO Mapping
The API layer returns DTOs. Query hooks map DTOs into entities before data reaches UI code.
```txt
data/mappers/AdminMapper.ts
data/mappers/RoleMapper.ts
data/mappers/PermissionMapper.ts
entities/AdminEntity.ts
entities/RoleEntity.ts
entities/PermissionEntity.ts
```
Keep backend response shape in DTOs. Keep UI/domain shape in entities.
## Forms
Admin form:
```txt
view/forms/AdminForm/
```
Responsibilities:
- Create and update admin data.
- Select admin status.
- Assign roles.
- Optionally update password.
Role form:
```txt
view/forms/RoleForm/
```
Responsibilities:
- Create and update role name.
- Group available permissions by module slug prefix.
- Assign permission slugs to the role.
## Widgets
| Widget | Purpose |
| -------------------- | -------------------------------------------- |
| `AdminTable` | Admin list, filters, actions, create button. |
| `RoleTable` | Role list, actions, create button. |
| `ManageAdminTrigger` | Admin create/edit dialog orchestration. |
| `ManageRoleTrigger` | Role create/edit dialog orchestration. |
| `DeleteAdminTrigger` | Admin delete confirmation and mutation. |
| `DeleteRoleTrigger` | Role delete confirmation and mutation. |
## Translations
Translations are module-local:
```txt
config/messages.ts
config/translation/en.json
config/translation/uk.json
```
Use only `ACCESS_CONTROL.*` keys inside this module.
@@ -0,0 +1,36 @@
# Account Settings Module
The Account Settings module provides the current admin user's profile settings screen. It lets the signed-in admin update profile fields and password, and view assigned roles.
## Source Map
| Area | Path |
| ------------------------- | ----------------------------------------------------------------------------- |
| Frontend module | `apps/admin/src/core/AccountSettings/` |
| Frontend routes | `apps/admin/src/core/AccountSettings/config/routing.tsx` |
| Frontend translations | `apps/admin/src/core/AccountSettings/config/translation/` |
| Auth provider dependency | `apps/admin/src/core/Auth/providers/AuthProvider/` |
| Backend profile endpoint | `backend/app/base_modules/Admin/controller/admin_controller.ts` |
| Backend profile validator | `backend/app/base_modules/Admin/validators/admin_update_profile_validator.ts` |
## Documentation
| Page | Purpose |
| ------------------------- | --------------------------------------------------------- |
| [Frontend](./frontend.md) | Route, page, form, profile update flow, and translations. |
| [Backend](./backend.md) | Current-user profile endpoint and validation. |
## Main Capabilities
- Display current authenticated admin profile.
- Update first name, last name, email, status, and optional password.
- Show assigned roles.
- Crop and stage an avatar image in the form UI.
- Use module-local translations through `ACCOUNT.*` keys.
## Ownership Rules
- AccountSettings owns the current-user profile UI.
- Auth owns current-user state, token storage, and API calls used by the profile page.
- Backend Admin owns profile persistence and validation.
- AccountSettings should not manage other admins; that belongs to AccessControl.
@@ -0,0 +1,69 @@
# Account Settings Backend
Account Settings does not have a separate backend base module. It uses the Admin backend module's current-user profile endpoint.
## Route
| Method | Route | Controller | Purpose |
| ------ | ----------------------- | ------------------------------- | ----------------------------------------- |
| `PUT` | `/admin/update-profile` | `AdminController.updateProfile` | Update the currently authenticated admin. |
Source:
```txt
backend/app/base_modules/Admin/routes.ts
backend/app/base_modules/Admin/controller/admin_controller.ts
```
The route uses `middleware.auth()`.
## Request Flow
```txt
PUT /admin/update-profile
-> auth middleware
-> AdminController.updateProfile
-> admin_update_profile_validator
-> current auth user merge/save
-> reload roles
-> query role_permissions
-> return { user, permissions }
```
## Validation
Validator:
```txt
backend/app/base_modules/Admin/validators/admin_update_profile_validator.ts
```
Keep frontend validation compatible with this validator. Backend validation is authoritative.
## Response Contract
The endpoint returns the same shape consumed by Auth:
```ts
type GetUserResponse = {
user: {
id: number;
email: string;
firstName: string;
lastName: string;
status: string;
createdAt: string;
roles: Array<{ id: number; name: string }>;
};
permissions: string[];
};
```
AuthProvider maps this response into `AuthUser` and updates current user state.
## Ownership Rules
- AccountSettings owns the UI and form behavior.
- Auth owns `updateUser` and current user state updates.
- Backend Admin owns profile persistence and response shape.
- AccessControl owns managing other admin accounts.
@@ -0,0 +1,103 @@
# Account Settings Frontend
The frontend module implements the current admin profile settings page.
Source root:
```txt
apps/admin/src/core/AccountSettings/
```
## Directory Structure
```txt
AccountSettings/
config/ Routes, messages, translations.
pages/ Profile route page.
view/
forms/ Profile form and form fields.
layouts/ Account layout.
```
## Routes
Frontend route config:
```txt
config/routing.tsx
```
Mounted module path:
```txt
/account/*
```
| Route | Page | Purpose |
| ------------------ | ------------- | ------------------------------- |
| `/account/profile` | `ProfilePage` | Current admin profile settings. |
The index route redirects to `/account/profile`.
## Profile Page
Main file:
```txt
pages/Profile/index.tsx
```
Responsibilities:
- Read the current user from `useAuth()`.
- Submit profile updates through `updateUser`.
- Map backend validation errors into form fields.
- Render assigned roles.
## Form
Profile form files:
```txt
view/forms/ProfileForm/Component.tsx
view/forms/ProfileForm/form.ts
view/forms/ProfileForm/fields/PasswordField.tsx
view/forms/ProfileForm/fields/AvatarCropperField.tsx
```
Password behavior:
- Password fields are hidden until toggled open.
- Password is optional.
- If provided, password must be at least 8 characters.
- If provided, confirmation must match.
Avatar behavior:
- The field supports local crop/preview UI.
- The form currently stages avatar data in the form value.
- Profile update payload strips avatar before calling `updateUser`.
## Auth Dependency
## Translations
Translations are module-local:
```txt
config/messages.ts
config/translation/en.json
config/translation/uk.json
```
Use only `ACCOUNT.*` keys inside this module.
## Common Change Guide
| Change | Start Here |
| ---------------------------- | ----------------------------------------------------------------------------- |
| Add a profile field | `ProfileForm/form.ts`, `ProfileForm/Component.tsx`, backend profile validator |
| Change password validation | `ProfileForm/form.ts` |
| Change avatar UI | `ProfileForm/fields/AvatarCropperField.tsx` |
| Change profile save behavior | `pages/Profile/index.tsx` and AuthProvider `updateUser` |
| Change translations | `config/translation/en.json` and `config/translation/uk.json` |
+39
View File
@@ -0,0 +1,39 @@
# Auth Module
The Auth module owns admin authentication, current-user state, token persistence, auth routes, and route guarding.
## Source Map
| Area | Path |
| --------------------- | -------------------------------------------------- |
| Frontend module | `apps/admin/src/core/Auth/` |
| Frontend routes | `apps/admin/src/core/Auth/config/routing.tsx` |
| Frontend provider | `apps/admin/src/core/Auth/providers/AuthProvider/` |
| Frontend translations | `apps/admin/src/core/Auth/config/translation/` |
| Backend module | `backend/app/base_modules/Auth/` |
| Backend admin model | `backend/app/base_modules/Admin/model/admin.ts` |
| Auth config | `backend/config/auth.ts` |
## Documentation
| Page | Purpose |
| ------------------------- | ------------------------------------------------------------------------------------- |
| [Frontend](./frontend.md) | AuthProvider, login page, route guard, token storage, and translations. |
| [Backend](./backend.md) | Login/logout/current-user routes, validators, token behavior, and response contracts. |
## Main Capabilities
- Sign in with admin email and password.
- Store bearer token client-side.
- Verify and load current authenticated admin.
- Expose current user, permissions, login, logout, verify, and profile update methods.
- Guard app routes until authentication is known.
- Clear React Query cache on logout.
## Ownership Rules
- Auth owns session state and current user state.
- Auth owns token persistence.
- Auth owns auth route UI and auth guard widget.
- AccountSettings may call AuthProvider `updateUser` but does not own auth state.
- Permission gates consume `AuthUser.permissions` but do not fetch auth state themselves.
+109
View File
@@ -0,0 +1,109 @@
# Auth Backend
The backend Auth module exposes token-based admin authentication routes.
Source root:
```txt
backend/app/base_modules/Auth/
```
## Routes
| Method | Route | Controller Method | Auth Required | Purpose |
| ------ | -------------- | ----------------- | ------------- | ------------------------------------------- |
| `POST` | `/auth/login` | `login` | No | Verify credentials and create bearer token. |
| `POST` | `/auth/logout` | `logout` | Yes | Invalidate current bearer token. |
| `GET` | `/auth/user` | `user` | Yes | Return current admin and permission slugs. |
Route file:
```txt
backend/app/base_modules/Auth/routes.ts
```
## Request Flow
### Login
```txt
POST /auth/login
-> auth_login_validator
-> Admin.findBy('email')
-> hash.verify(password)
-> Admin.accessTokens.create(admin)
-> return { type, token, user }
```
### Current User
```txt
GET /auth/user
-> auth middleware
-> auth.use('api').user
-> load roles
-> query role_permissions
-> return { user, permissions }
```
## Validation
Login validator:
```txt
backend/app/base_modules/Auth/validators/auth_login_validator.ts
```
Current rules:
- `email`: trimmed email string.
- `password`: trimmed string with minimum length 8.
## Token Guard
Auth config:
```txt
backend/config/auth.ts
```
The admin model is configured as the token user provider:
```txt
backend/app/base_modules/Admin/model/admin.ts
```
## Response Contracts
Login response consumed by frontend:
```ts
type LoginResponse = {
type: "bearer";
token: string;
user: unknown;
};
```
Current-user response consumed by frontend:
```ts
type GetUserResponse = {
user: {
id: number;
email: string;
firstName: string;
lastName: string;
status: string;
createdAt: string;
roles: Array<{ id: number; name: string }>;
};
permissions: string[];
};
```
## Ownership Rules
- Auth backend owns token creation, token invalidation, and current-user response shape.
- Admin backend owns admin persistence and profile updates.
- Permission data in `/auth/user` is derived from role-permission rows.
+131
View File
@@ -0,0 +1,131 @@
# Auth Frontend
The frontend module implements authentication screens, session provider, current-user loading, and route guards.
Source root:
```txt
apps/admin/src/core/Auth/
```
## Directory Structure
```txt
Auth/
config/ Routes, messages, translations.
data/
api/ Raw auth/profile API calls and DTOs.
mappers/ Current-user DTO mapping.
stores/ Local token storage helpers.
entities/ Auth and user types.
pages/ Sign-in page.
providers/ AuthProvider and context.
view/
forms/ Sign-in form.
layouts/ Auth layouts.
widgets/ Auth guard.
```
## Routes
Frontend route config:
```txt
config/routing.tsx
```
Mounted module path:
```txt
/auth/*
```
| Route | Page | Purpose |
| -------------- | ------------ | --------------------- |
| `/auth/signin` | `SignInPage` | Admin sign-in screen. |
The index route redirects to `signin`.
## AuthProvider
Provider file:
```txt
providers/AuthProvider/AuthProvider.tsx
```
Exposes:
```ts
auth;
user;
loading;
login(email, password);
logout();
verify();
getUser();
updateUser(payload);
saveAuth(auth);
setUser(user);
```
Important behavior:
- `login` stores the access token, then loads the current user.
- `verify` reloads current user when a token exists.
- `logout` calls the backend, clears auth state, and clears React Query cache.
- `updateUser` calls `/admin/update-profile` and updates current user state.
## API Boundary
Raw API calls:
```txt
data/api/api.ts
data/api/dto.ts
```
| Method | Backend Route | Purpose |
| ------------ | --------------------------- | ---------------------------------- |
| `login` | `POST /auth/login` | Create bearer token. |
| `logout` | `POST /auth/logout` | Invalidate current token. |
| `getUser` | `GET /auth/user` | Load current user and permissions. |
| `updateUser` | `PUT /admin/update-profile` | Update current admin profile. |
Current-user DTO mapping:
```txt
data/mappers/userMapper.ts
```
## Token Storage
Token persistence helpers live in:
```txt
data/stores/localStorage.ts
```
Keep token storage behind these helpers so storage format changes stay local.
## Route Guard
Auth guard widget:
```txt
view/widgets/AuthGuardWidget.tsx
```
Use this widget to protect authenticated app routes. It coordinates auth loading and redirects unauthenticated users to auth routes.
## Translations
Translations are module-local:
```txt
config/messages.ts
config/translation/en.json
config/translation/uk.json
```
Use only `AUTH.*` keys inside this module.
@@ -0,0 +1,47 @@
# Fallback Screens Module
The Fallback Screens module owns route-level and reusable fallback pages in the admin app. It currently provides HTTP-style error screens for forbidden, not found, and server error states, and it is the intended home for future fallback pages such as maintenance, unavailable, empty-state, or generic recovery screens.
## Source Map
| Area | Path |
| --------------------- | ------------------------------------------------------------ |
| Frontend module | `apps/admin/src/core/FallbackScreens/` |
| Frontend routes | `apps/admin/src/core/FallbackScreens/config/routing.tsx` |
| Frontend translations | `apps/admin/src/core/FallbackScreens/config/translation/` |
| Frontend layout | `apps/admin/src/core/FallbackScreens/view/layouts/` |
| Backend module | Not applicable. Fallback Screens is currently frontend-only. |
## Documentation
| Page | Purpose |
| ------------------------- | ----------------------------------------------------------------- |
| [Frontend](./frontend.md) | Routes, page structure, translations, ownership, and conventions. |
| [Backend](./backend.md) | Backend ownership notes and when a backend change may be needed. |
## Main Capabilities
- Render full-page fallback screens under `/error/*`.
- Provide reusable fallback page components for other core modules.
- Keep fallback screen translations module-local.
- Provide a consistent layout for fallback pages.
- Preserve stable public fallback URLs such as `/error/403`, `/error/404`, and `/error/500`.
## Ownership Rules
- FallbackScreens owns fallback page UI, fallback routing, and fallback-specific translations.
- Other modules may import reusable fallback pages, for example permission gates using `Error403Page`.
- Shared API/query error parsing does not belong here; keep it in shared error/query utilities.
- Domain-specific empty states should stay in the owning domain module unless they are generic enough to reuse across modules.
- Backend modules own the actual API status codes and response payloads. FallbackScreens only decides how the admin frontend presents fallback states.
## Common Change Guide
| Change | Start Here |
| ------------------------------ | ------------------------------------------------------------------------------ |
| Add a new fallback route | `apps/admin/src/core/FallbackScreens/config/routing.tsx` |
| Add a new fallback page | `apps/admin/src/core/FallbackScreens/pages/` |
| Change fallback page layout | `apps/admin/src/core/FallbackScreens/view/layouts/FallbackScreensLayout.tsx` |
| Change translations | `apps/admin/src/core/FallbackScreens/config/translation/en.json` and `uk.json` |
| Reuse a fallback in a module | Export it from `apps/admin/src/core/FallbackScreens/index.ts` |
| Change global fallback routing | `apps/admin/src/app/routing/app_routing_setup.tsx` |
@@ -0,0 +1,29 @@
# Fallback Screens Backend
Fallback Screens is currently a frontend-only core module.
There is no backend source folder for this module.
## Backend Relationship
Backend modules may return HTTP status codes or API error payloads that eventually lead the admin frontend to show a fallback screen, but the fallback UI is owned by:
```txt
apps/admin/src/core/FallbackScreens/
```
Examples:
| Status | Frontend fallback | Notes |
| ------ | ---------------------- | --------------------------------------------- |
| `403` | `/error/403` or inline | Used for permission denied states. |
| `404` | `/error/404` | Used for unknown frontend routes. |
| `500` | `/error/500` | Used for generic server failure presentation. |
## When Backend Changes Are Needed
Backend changes are only needed when:
- A backend endpoint should return a different status code.
- A redirect or auth flow should navigate the frontend to a fallback route.
- A feature needs a new machine-readable error contract that the frontend can map to a fallback screen.
@@ -0,0 +1,83 @@
# Fallback Screens Frontend
The frontend module provides fallback UI for app-level error and recovery states.
Source root:
```txt
apps/admin/src/core/FallbackScreens/
```
## Directory Structure
```txt
FallbackScreens/
config/ Routes, messages, and translations.
pages/ Route-level fallback pages.
view/
layouts/ Shared fallback page layout.
```
## Routes
Frontend route config:
```txt
config/routing.tsx
```
Mounted route path:
```txt
/error/*
```
| Route | Page | Purpose |
| ------------ | -------------- | ------------------------------------ |
| `/error` | `Error404Page` | Default fallback route. |
| `/error/403` | `Error403Page` | Forbidden or permission denied page. |
| `/error/404` | `Error404Page` | Not found page. |
| `/error/500` | `Error500Page` | Internal server error page. |
Unknown `/error/*` paths redirect to `/error/404`.
## App Integration
The app-level router mounts `fallbackScreensRoute` from:
```txt
apps/admin/src/app/routing/app_routing_setup.tsx
```
The app-level i18n config merges `fallbackScreensMessages` from:
```txt
apps/admin/src/app/i18n/config.ts
```
## Translations
Translations are module-local:
```txt
config/messages.ts
config/translation/en.json
config/translation/uk.json
```
Use only `FALLBACK_SCREENS.*` keys inside this module.
Do not put fallback page strings in app-level files such as:
```txt
apps/admin/src/app/i18n/messages/en.json
apps/admin/src/app/i18n/messages/uk.json
```
## Page Conventions
- Keep route-level fallback pages under `pages/*Page/index.tsx`.
- Keep shared wrapper layout under `view/layouts/`.
- Keep public URLs stable unless there is a migration plan.
- Prefer module-local translation keys for all visible text, including generic-looking actions like return-home links.
- Add a route only when the fallback is intended to be navigable. Inline-only reusable fallbacks can be exported without a route.
+106
View File
@@ -0,0 +1,106 @@
# File Manager Module
The File Manager module provides authenticated file browsing and file operations for the admin app. It has a backend API for storage operations and a frontend UI for browsing, previewing, uploading, renaming, deleting, duplicating, and editing supported files.
## Source Map
| Area | Path |
| ---------------------- | ------------------------------------------------------------------------------------- |
| Backend module | `backend/app/base_modules/FileManager/` |
| Backend storage config | `backend/config/drive.ts` |
| Backend S3 adapter | `backend/app/base_modules/FileManager/services/storage_service/s3_storage_service.ts` |
| Frontend module | `apps/admin/src/core/FileManager/` |
| Frontend file assets | `apps/admin/public/media/files/` |
| Frontend routes | `apps/admin/src/core/FileManager/config/routing.tsx` |
## Documentation
| Page | Purpose |
| ------------------------- | ---------------------------------------------------------------------------------- |
| [Backend](./backend.md) | API routes, services, storage adapter contract, permissions, and extension points. |
| [Frontend](./frontend.md) | UI structure, React Query and MobX, cache updates, pages, and widgets. |
## Main Capabilities
- Browse folders and files.
- Filter, sort, and paginate directory entries.
- Preview file details and text content for supported extensions.
- Stream raw files for preview or download.
- Create folders.
- Upload files with progress and cancellation support.
- Rename, delete, and duplicate entries.
- Search entries.
- Open an image editor for image files.
- Pick files through reusable frontend picker components.
- Insert files into RichText editor through reusable frontend picker components.
- Use local filesystem storage or S3-compatible storage through Adonis Drive.
## High-Level Flow
```txt
Admin route
-> FileManager frontend page
-> React Query API hook
-> /file-manager backend route
-> FileManagerController
-> FileManagerService
-> StorageService adapter
-> Adonis Drive fs or s3 disk
```
## Data Contract
Backend responses use `Entry` objects:
```ts
type Entry = FileEntry | FolderEntry;
type FileEntry = {
type: "file";
name: string;
path: string;
url: string;
size?: number;
updatedAt?: string;
};
type FolderEntry = {
type: "folder";
name: string;
path: string;
updatedAt?: string;
};
```
The frontend maps DTOs into frontend entities and adds UI-oriented metadata such as `parent` and `extension`.
## Ownership Rules
- Backend owns storage, validation, authorization, path safety, and API response shape.
- Frontend owns navigation, selection, view settings, operation progress, and user interactions.
- React Query owns server state in the frontend.
- MobX stores own local UI and operation state in the frontend.
- Storage adapters must implement `storage_service_interface.ts`; callers should depend on that interface, not a concrete disk implementation.
- The active storage adapter is selected by `DRIVE_DISK`.
## Common Change Guide
| Change | Start Here |
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| Add or change an API route | `backend/app/base_modules/FileManager/routes.ts` and `controller/file_manager_controller.ts` |
| Change path validation or naming rules | `services/path_service.ts` |
| Change list filtering, sorting, or pagination | `services/entry_list_service.ts` and frontend query payloads |
| Add or change a storage backend | `services/storage_service/storage_service_interface.ts`, `create_storage_service.ts`, and [Backend storage docs](./backend.md#storage) |
| Add a frontend operation | `apps/admin/src/core/FileManager/data/queries/` and relevant store/widget |
| Add file type icons | `apps/admin/public/media/files/` and `shared/file/fileTypeImportMap.ts` |
| Add preview support | Backend `file_preview_service.ts` and frontend `view/ui/FilePreview/` |
## Planned Work
- Add more non-filesystem storage adapters such as:
- Google Cloud Storage
- Supabase Storage
- Digital Ocean Spaces
- Cloudflare R2
- Add testing notes once module-level backend and frontend tests are established.
- Add libs for rendering large lists.
+368
View File
@@ -0,0 +1,368 @@
# File Manager Backend
The backend module exposes authenticated file operations under `/file-manager`. It validates requests, authorizes actions, normalizes paths, orchestrates file-manager behavior, and delegates raw storage work to a storage adapter.
Source root:
```txt
backend/app/base_modules/FileManager/
```
## Request Flow
```txt
routes.ts
-> controller/file_manager_controller.ts
-> validator/*
-> policy/file_manager_policy.ts
-> services/file_manager_service.ts
-> services/storage_service/storage_service_interface.ts
-> services/storage_service/create_storage_service.ts
-> services/storage_service/fs_storage_service.ts | services/storage_service/s3_storage_service.ts
-> Adonis Drive
```
The controller should stay thin. It handles HTTP concerns: auth policy checks, request validation, path extraction, status codes, and response payload shape.
`FileManagerService` owns business orchestration. Storage adapters own raw persistence operations.
## Routes
All routes are prefixed with `/file-manager` and use `middleware.auth()`.
| Method | Route | Controller Method | Purpose |
| -------- | ------------------ | ----------------- | ------------------------------------------------------- |
| `GET` | `/` | `index` | List root directory entries. |
| `GET` | `/*` | `index` | List entries for a nested directory. |
| `GET` | `/files/details/*` | `show` | Return file metadata and optional text preview content. |
| `GET` | `/files/raw/*` | `raw` | Stream raw file content. |
| `GET` | `/search?q=value` | `search` | Search entries recursively. |
| `POST` | `/folders` | `createFolder` | Create a folder. |
| `POST` | `/files` | `upload` | Upload a file. |
| `POST` | `/files/duplicate` | `duplicate` | Duplicate one or more **file** entries. |
| `PUT` | `/entries/rename` | `rename` | Rename or move an entry within its parent path. |
| `DELETE` | `/*` | `destroy` | Delete an entry. |
## Authorization
Policy file:
```txt
policy/file_manager_policy.ts
```
Controller methods call policy abilities before performing work:
| Ability | Used By |
| ---------- | ---------------------------------------------- |
| `viewList` | List entries, search entries. |
| `view` | File details, raw file stream. |
| `create` | Create folder, upload file, duplicate entries. |
| `update` | Rename entry. |
| `delete` | Delete entry. |
When adding a new operation, add or reuse an explicit policy ability before adding service logic.
## Validation
Validators live in:
```txt
validator/
```
Current validators:
| File | Purpose |
| -------------------------------- | ----------------------------------------------------------------- |
| `list_validator.ts` | Validates filter, sort, order, max results, and pagination token. |
| `create_directory_validator.ts` | Validates parent path and folder name. |
| `rename_entry_validator.ts` | Validates source path and new name. |
| `upload_file_validator.ts` | Validates upload path and file payload. |
| `duplicate_entries_validator.ts` | Validates duplicate source paths. |
| `schemas.ts` | Shared validation schema helpers. |
Path extraction from wildcard routes goes through:
```txt
helpers/get_validated_path_from_request.ts
```
Keep path validation centralized. Avoid parsing wildcard paths directly in controllers or storage adapters.
## Services
### `file_manager_service.ts`
Main orchestration service.
Responsibilities:
- List directory entries with filtering, sorting, and pagination.
- Compose file detail responses with preview content.
- Create directory response entries.
- Validate and move entries.
- Generate unique upload names.
- Generate duplicate copy names.
- Search entries.
- Coordinate storage adapter calls.
### `path_service.ts`
Shared path and filename utility service.
Responsibilities:
- Convert client paths to storage paths.
- Convert storage paths to client paths.
- Join paths safely.
- Get dirname and basename.
- Parse file extension metadata.
- Sanitize filenames.
- Generate unique names.
Use this service for path behavior instead of string manipulation in feature code.
### `entry_list_service.ts`
Applies list behavior to raw storage entries.
Responsibilities:
- Filter entries by category.
- Sort entries.
- Keep folders before files.
- Paginate entries.
- Encode and decode pagination tokens.
Frontend list controls must stay compatible with this service's accepted filter and sort values.
### `file_preview_service.ts`
Adds text preview content to previewable files.
Previewable text extensions are currently defined in:
```txt
services/file_preview_service.ts
```
If a file type needs rich frontend preview, keep the backend response small and stream raw content through `/files/raw/*` when possible.
### `entry_search_service.ts`
Searches entries by path and includes matching parent folders so the frontend can display useful context.
Search receives an abort signal from the controller. Long-running search implementations should respect that signal.
## Storage
Storage abstractions live in:
```txt
services/storage_service/
```
### `storage_service_interface.ts`
Defines the storage adapter contract. Adapters expose raw operations:
- List directory entries.
- List recursive entries.
- Check entry existence.
- Get file metadata.
- Read file content.
- Stream file content.
- Write file.
- Create directory.
- Move entry.
- Delete entry.
- Copy entry.
Services should call the interface, not a concrete adapter.
### `fs_storage_service.ts`
Filesystem storage adapter.
Responsibilities:
- Call the Adonis Drive filesystem disk.
- Map filesystem objects to File Manager entries.
- Handle file streams and metadata.
- Create, move, copy, and delete filesystem entries.
- Preserve filesystem directory marker behavior.
### `s3_storage_service.ts`
S3-compatible storage adapter.
Responsibilities:
- Call the Adonis Drive `s3` disk.
- Map S3 objects and common prefixes to File Manager entries.
- Upload multipart files by streaming the temporary upload file into S3 with `putStream`.
- Read file content and streams from S3.
- Create folders with directory marker objects.
- Move folders by moving every object under the folder prefix.
- Delete files with exact object deletion and folders with folder-prefix deletion.
- Copy file entries.
S3 has no native directories. The adapter uses the same `.keep` marker convention as the filesystem adapter so empty folders can exist.
Folder operations must use slash-terminated prefixes. For example, deleting `test/` must not delete objects such as `test123.txt`.
### `fs_directory_marker_service.ts`
Encapsulates the filesystem directory marker convention.
Current marker:
```txt
.keep
```
Do not duplicate marker logic outside this service. Storage adapters that need virtual folders should use this marker service behind the storage interface.
### `create_storage_service.ts`
Storage service factory.
Current supported storage:
```txt
fs
s3
```
The active adapter is selected by `DRIVE_DISK`.
```env
DRIVE_DISK=fs
```
or:
```env
DRIVE_DISK=s3
```
## Drive Configuration
Adonis Drive config lives in:
```txt
backend/config/drive.ts
```
Configured disks:
| Disk | Driver | Purpose |
| ---- | ------------- | ---------------------------------------------------- |
| `fs` | `services.fs` | Local development and filesystem-backed storage. |
| `s3` | `services.s3` | S3-compatible object storage, including local MinIO. |
The S3 disk expects these environment variables:
| Variable | Local Docker Value | Purpose |
| ----------------------- | --------------------------------------------------------------------- | --------------------------------------------- |
| `AWS_ACCESS_KEY_ID` | `minioadmin` | S3 access key. |
| `AWS_SECRET_ACCESS_KEY` | `minioadmin` | S3 secret key. |
| `AWS_REGION` | `us-east-1` | S3 region. |
| `S3_BUCKET` | `crux-drive` | Bucket used by the file manager. |
| `S3_ENDPOINT` | `http://minio:9000` in Docker, `http://localhost:9000` outside Docker | S3 API endpoint. |
| `S3_CDN_URL` | `http://localhost:9000/crux-drive/` | Browser-facing public URL base for file URLs. |
For MinIO, the S3 disk uses path-style addressing:
```ts
forcePathStyle: true;
```
The adapter also disables ACL API calls:
```ts
supportsACL: false;
```
Bucket public-read behavior is handled by the Docker bucket setup container.
## Local S3 Simulation
Local S3 is simulated with MinIO in:
```txt
docker-compose.yml
```
Services:
| Service | Purpose |
| --------------------- | --------------------------------------------------------------------------------------- |
| `minio` | Runs the S3-compatible object storage server. |
| `minio_create_bucket` | One-shot setup container that creates the bucket and enables anonymous download access. |
MinIO console:
```txt
http://localhost:9001
```
Default local credentials:
```txt
user: minioadmin
pass: minioadmin
```
The `minio_create_bucket` container is expected to exit after setup. A stopped container with successful bucket logs is normal.
To rebuild after dependency or Dockerfile changes:
```sh
docker compose build --no-cache
docker compose up
```
## Response Shape
Directory and file operations return `Entry` objects:
```ts
interface EntryBase {
name: string;
path: string;
updatedAt?: string;
}
interface FileEntry extends EntryBase {
type: "file";
size?: number;
url: string;
}
interface FolderEntry extends EntryBase {
type: "folder";
}
```
List responses include pagination metadata:
```ts
{
data: Entry[];
meta: {
nextPaginationToken: string | null;
};
}
```
## Backend Change Checklist
Before changing backend behavior:
1. Confirm the policy ability for the operation.
2. Add or update a validator for all request input.
3. Keep client paths and storage paths separated through `path_service.ts`.
4. Update the frontend DTO or mapper if response shape changes.
5. Update this documentation when routes, permissions, storage contracts, or response shapes change.
+439
View File
@@ -0,0 +1,439 @@
# File Manager Frontend
The frontend module implements the admin file manager UI. It provides file browsing, previews, uploads, deletion, duplication, renaming, image editing, settings, and reusable file picker widgets.
This module follows the general [React frontend architecture](../../apps-architecture/react-frontend/Readme.md) inside its own module boundary.
Source root:
```txt
apps/admin/src/core/FileManager/
```
## Main Principle
React Query owns server state. MobX owns local UI and operation state.
Server state examples:
- Directory entries.
- File details.
- Raw file blobs.
- Search results.
- Create, rename, delete, duplicate, and upload mutations.
Local state examples:
- Active path.
- Selected paths.
- Expanded tree paths.
- Filter and sort controls.
- Dialog open state.
- Upload and delete operation progress.
- Cached lookup of already loaded entries for UI behavior.
## Directory Structure
```txt
FileManager/
config/ Routes, menu entries, messages, translations.
data/
api/ Raw HTTP methods and DTOs.
hooks/ Feature hooks that combine queries with stores.
mappers/ DTO-to-entity mapping.
queries/ React Query hooks, keys, mutations, and cache helpers.
stores/ MobX local state stores.
entities/ Domain entities and settings types.
providers/ Feature providers and context hooks.
pages/ Route-level screens.
shared/ FileManager utilities that do not depend on view code.
view/ UI components, widgets, forms, and layouts.
```
## Routes
Frontend route config:
```txt
config/routing.tsx
```
Mounted module path:
```txt
/file-manager/*
```
Current child routes:
| Route | Page | Purpose |
| -------------------------------- | ------------------- | ----------------------------------- |
| `/file-manager/drive/explorer/*` | `DriveExplorerPage` | Browse folders and files. |
| `/file-manager/drive/viewer/-/*` | `DriveViewerPage` | View file details and preview. |
| `/file-manager/drive/settings` | `DriveSettingsPage` | Configure file-manager UI settings. |
| `/file-manager/editor/image/-/*` | `ImageEditorPage` | Edit image files. |
Path helpers live in:
```txt
shared/routing/driveLinks.ts
shared/routing/openEntryNewTab.ts
shared/path/leadingSlash.ts
```
Use these helpers instead of manually building file-manager URLs.
## API Boundary
Raw backend calls are centralized in:
```txt
data/api/api.ts
data/api/dto.ts
```
The frontend calls the backend routes documented in [backend.md](./backend.md):
| API Method | Backend Route |
| ----------------- | ------------------------------------ |
| `getEntries` | `GET /file-manager/*` |
| `getFile` | `GET /file-manager/files/details/*` |
| `getRawFile` | `GET /file-manager/files/raw/*` |
| `createDirectory` | `POST /file-manager/folders` |
| `renameEntry` | `PUT /file-manager/entries/rename` |
| `removeEntry` | `DELETE /file-manager/*` |
| `uploadFile` | `POST /file-manager/files` |
| `duplicateFiles` | `POST /file-manager/files/duplicate` |
| `searchEntries` | `GET /file-manager/search` |
DTOs should be mapped before they reach UI code. Entity types live in:
```txt
entities/entry.ts
data/mappers/entryMapper.ts
```
## Data Flow
### Reading Entries
Directory entries are fetched through:
```ts
useGetEntries();
```
The higher-level hook:
```ts
useEntries();
```
does three things:
1. Builds the query payload from `ExplorerStore`.
2. Fetches entries with React Query.
3. Syncs loaded entries into `EntriesStore`.
`EntriesStore` is not the fetch owner. It is an index of loaded entries used by the sidebar tree, selection lookups, active entry lookup, and operation state.
### Deep Links
When opening a nested folder directly, `useEntries()` preloads ancestor folders through React Query. This keeps the sidebar tree and entry index usable for paths like:
```txt
/folder/subfolder/current
```
### Mutations
Mutations use React Query hooks:
- `useCreateDirectory`
- `useRenameEntry`
- `useDeleteEntry`
- `useDuplicateFiles`
- `useUploadFile`
After a successful mutation, the UI updates local cache and stores directly. It does not invalidate entries queries after every operation.
This avoids unnecessary refetches when many items are created, deleted, or uploaded in sequence.
## Query Cache Updates
Entries cache helpers live in:
```txt
data/queries/cache.ts
```
Current helpers:
```ts
addEntriesToCache(parentPath, entries);
removeEntriesFromCache(paths);
renameEntryInCache(prevPath, renamedEntry);
```
These helpers update existing React Query cache data in memory. They do not trigger a network request.
Important behavior:
- Added entries are inserted into cached lists for the matching parent folder.
- Added entries are filter-aware.
- Deleted entries are removed from all cached entry pages.
- Renamed entries are updated across cached entry pages.
Tradeoff: because the module avoids refetching, exact backend sort order may not be perfect after local cache insertion until the folder is naturally refetched or reloaded.
## Stores
### `EntriesStore`
File:
```txt
data/stores/entriesStore.ts
```
Purpose:
- Keep an index of loaded entries by path.
- Provide child lookup by parent path.
- Support selected-entry and active-entry lookup.
- Support local remove and rename updates for already loaded subtrees.
It should not fetch data.
### `ExplorerStore`
File:
```txt
data/stores/explorerStore.ts
```
Purpose:
- Active path.
- Selected paths.
- Expanded tree paths.
- Breadcrumbs.
- Entries filter.
- Sort field and direction.
### `DriveDialogStore`
File:
```txt
data/stores/driveDialogStore.ts
```
Purpose:
- Create-directory dialog state.
- Rename-entry dialog state.
- Current entry selected for rename.
### `UploadOperationStore`
File:
```txt
data/stores/uploadOperationStore.ts
```
Purpose:
- Upload queue.
- Upload progress.
- Upload retry, remove, and abort.
- Upload operation card visibility.
It receives the React Query mutation function from the view layer and manages only operation state.
### `DeleteOperationStore`
File:
```txt
data/stores/deleteOperationStore.ts
```
Purpose:
- Delete queue.
- Delete progress.
- Delete retry and remove.
- Delete operation card visibility.
It receives the React Query mutation function from the view layer and manages only operation state.
### `SettingsStore`
File:
```txt
data/stores/settingsStore.ts
```
Purpose:
- Persisted view mode.
- Compact mode.
- Sidebar visibility.
- Grid size and related display preferences.
## Providers
`DriveProvider` creates and exposes feature stores:
```ts
entriesStore;
explorerStore;
driveDialogStore;
uploadOperationStore;
deleteOperationStore;
```
Use:
```ts
const { entriesStore, explorerStore } = useDrive();
```
`SettingsProvider` owns persisted settings such as view mode, compact mode, sidebar visibility, and grid size.
## Pages And Widgets
### `DriveExplorerPage`
Main file browser page. Composes:
- `DriveProvider`
- Explorer toolbar.
- Explorer content.
- Explorer sidebar.
- Footer.
- Operation watcher.
### `DriveViewerPage`
File details and preview page. Uses:
```ts
useGetFile();
```
### `DriveSettingsPage`
Settings page for persisted file-manager UI preferences.
### `ImageEditorPage`
Image editor page. Uses:
```ts
useGetFile();
useGetRawFile();
useUploadFile();
```
Image editor config and helpers live in the widget layer:
```txt
view/widgets/ImageEditor/config.ts
view/widgets/ImageEditor/helpers.ts
```
This prevents `view` code from importing from `pages`.
### `FilePickerDialog`
Reusable picker widgets live in:
```txt
view/widgets/FilePickerDialog/
```
Keep picker behavior feature-scoped, but pass reusable UI state through props and context instead of coupling low-level UI components to page-level stores.
## View Layer Rules
Feature widgets may use File Manager providers such as `useDrive()` and `useSettings()`.
Lower-level reusable UI components should stay prop-driven. Examples:
- `ExplorerFileEntryGrid`
- `ExplorerFolderEntryList`
- `ExplorerToolbarFilterDropdown`
- `FileManagerFileIcon`
- `FilePreview`
Do not import backend DTOs into view components. View components should consume frontend entities and props.
## File Types And Icons
File helpers live in:
```txt
shared/file/
```
File icons live in:
```txt
apps/admin/public/media/files/
```
To add or change an icon:
1. Add the asset under `apps/admin/public/media/files/`.
2. Update `shared/file/fileTypeImportMap.ts`.
3. Confirm `FileManagerFileIcon` renders the expected fallback for unknown extensions.
## Adding A New Query
1. Add or reuse a method in:
```txt
data/api/api.ts
```
2. Add a key in:
```txt
data/queries/keys.ts
```
3. Create a query file:
```txt
data/queries/example.ts
```
4. Map DTOs to entities before returning app-facing data.
Do not import MobX stores or providers inside `data/queries`.
## Adding A New Mutation
1. Add a raw API method in `data/api/api.ts`.
2. Add a mutation hook in `data/queries`.
3. In the consuming widget or operation store flow, call `mutateAsync`.
4. Update `EntriesStore` if lookup state must change.
5. Update `data/queries/cache.ts` helpers if visible query cache must change.
Do not invalidate entries queries after each operation unless a full refetch is intentionally required.
## Frontend Change Checklist
Before changing frontend behavior:
1. Identify whether the data is server state or local UI state.
2. Keep backend calls in `data/api`.
3. Keep React Query hooks free of MobX provider imports.
4. Map DTOs before passing data to view components.
5. Update cache helpers when mutation results should appear immediately.
6. Update backend docs if the frontend change requires a backend contract change.
+46
View File
@@ -0,0 +1,46 @@
# Permission Module
The Permission module provides frontend permission checks and gates. It also corresponds to the backend permission endpoint and permission discovery service used by AccessControl.
## Source Map
| Area | Path |
| -------------------------- | -------------------------------------------------------- |
| Frontend module | `apps/admin/src/core/Permission/` |
| Frontend gates | `apps/admin/src/core/Permission/view/gates/` |
| Frontend hook | `apps/admin/src/core/Permission/hooks/usePermissions.ts` |
| Frontend types | `apps/admin/src/core/Permission/entities/permission.ts` |
| Backend module | `backend/app/base_modules/Permission/` |
| Backend permission service | `backend/app/services/permission_service.ts` |
## Documentation
| Page | Purpose |
| ------------------------- | ------------------------------------------------------------------ |
| [Frontend](./frontend.md) | Permission types, hook, gates, and usage rules. |
| [Backend](./backend.md) | Permission endpoint, permission discovery, and permission configs. |
## Main Capabilities
- Check whether current user has required permission slugs.
- Support `all` and `any` matching modes.
- Render or hide UI actions through `PermissionGate`.
- Protect full pages through `PermissionPageGate`.
- Treat super admin as an all-permissions user.
## High-Level Flow
```txt
AuthProvider current user
-> AuthUser.permissions
-> usePermissions()
-> hasPermission()
-> PermissionGate or PermissionPageGate
```
## Ownership Rules
- Permission frontend owns permission checks and gate components.
- Auth owns loading current user permissions.
- AccessControl owns managing roles and assigning permissions.
- Backend modules own their own permission definitions in `config/permissions.ts`.
+81
View File
@@ -0,0 +1,81 @@
# Permission Backend
The backend Permission module exposes available permission definitions. It is used by AccessControl when assigning permissions to roles.
Source root:
```txt
backend/app/base_modules/Permission/
```
## Route
| Method | Route | Controller Method | Auth Required | Purpose |
| ------ | ------------- | ----------------- | ------------- | -------------------------------------------- |
| `GET` | `/permission` | `index` | Yes | Return all available permission definitions. |
Route file:
```txt
backend/app/base_modules/Permission/routes.ts
```
## Request Flow
```txt
GET /permission
-> auth middleware
-> PermissionController.index
-> getAllPermissions()
-> scan backend module permission configs
-> return PermissionItem[]
```
## Permission Discovery
Permission discovery lives in:
```txt
backend/app/services/permission_service.ts
```
`getAllPermissions()` scans:
```txt
backend/app/base_modules/*/config/permissions.ts
backend/app/modules/*/config/permissions.ts
```
Each config exports permission items:
```ts
type PermissionItem = {
slug: string;
name: string;
};
```
## Current Permission Configs
Core permission definitions currently include:
```txt
backend/app/base_modules/Admin/config/permissions.ts
backend/app/base_modules/Role/config/permissions.ts
backend/app/base_modules/FileManager/config/permissions.ts
```
When adding a feature that needs access control, add permission definitions to the owning backend module's `config/permissions.ts`.
## Admin Permission Slugs
`getAdminPermissionSlugs(admin)` loads an admin's roles and returns a set of permission slugs from `role_permissions`.
This function is used by backend policies to authorize operations.
## Ownership Rules
- Backend modules own their own permission definitions.
- Permission service owns discovering all available permission definitions.
- AccessControl owns assigning permission slugs to roles.
- Auth owns returning the current user's permission slugs to the frontend.
+102
View File
@@ -0,0 +1,102 @@
# Permission Frontend
The frontend module provides reusable permission-checking primitives for the admin app.
Source root:
```txt
apps/admin/src/core/Permission/
```
## Directory Structure
```txt
Permission/
config/ Static module config and messages.
entities/ Permission types.
hooks/ Current-user permission hook.
lib/ Pure permission check function.
view/gates/ React gate components.
```
## Types
Permission types live in:
```txt
entities/permission.ts
```
Key concepts:
```ts
type PermissionCheckMode = "all" | "any";
type RequiredPermissions = string | string[];
```
## Hook
Current-user permission access:
```txt
hooks/usePermissions.ts
```
The hook reads auth state from AuthProvider and returns:
```ts
permissions;
isAdmin;
loading;
```
`isAdmin` is based on the configured super admin id.
## Pure Permission Check
Permission check logic:
```txt
lib/hasPermission.ts
```
Behavior:
- Super admin passes all checks.
- `all` mode requires every permission.
- `any` mode requires at least one permission.
- Empty required permissions should be treated carefully at call sites.
## Gates
### `PermissionGate`
Use for conditional UI controls such as buttons and menu items.
```tsx
<PermissionGate requiredPermissions="admins.update">
<Button>Edit</Button>
</PermissionGate>
```
### `PermissionPageGate`
Use for route-level access protection.
```tsx
<PermissionPageGate requiredPermissions={["admins.view", "role.view"]}>
<AdminListPage />
</PermissionPageGate>
```
If access is denied, it renders the provided fallback or a 403 page.
## Translations
The module has a local message bundle for consistency:
```txt
config/messages.ts
config/translation/en.json
config/translation/uk.json
```