Initial commit
This commit is contained in:
@@ -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` |
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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`.
|
||||
@@ -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.
|
||||
@@ -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
|
||||
```
|
||||
Reference in New Issue
Block a user