📋 Система Permissions

Полное руководство по работе с иерархическими разрешениями

✅ 97+ тестов | 85% покрытие | Production Ready
← Назад к документации

🎯 Обзор Системы

Система permissions в StoreApp обеспечивает гибкий и мощный контроль доступа к документам через иерархическую модель разрешений. Система поддерживает 5 типов областей действия (scope), 3 уровня доступа и дополнительные фильтры для точной настройки прав.

97+
Тестов
85%
Покрытие
5
Типов Scope
<50ms
Проверка
✅ Production Ready

Система полностью протестирована и готова к использованию в продакшене. Все edge cases покрыты, производительность оптимизирована, аудит включен.

Ключевые Возможности

Иерархические уровни доступа (read < write < admin)
5 типов областей действия: от одного документа до всего приложения
Гибкое расшаривание: приложение-приложение, пользователю, публичные ссылки
Дополнительные фильтры по MIME типам, тегам, атрибутам, датам
Автоматическое истечение и ручной отзыв разрешений
Полный аудит всех операций с разрешениями
Массовая фильтрация до 100K документов за раз

🏗️ Архитектура

Система построена по принципам Clean Architecture и Domain-Driven Design, что обеспечивает четкое разделение ответственности и легкость тестирования.

📡 HTTP Layer
internal/delivery/http/handler/permission_handler.go
REST API endpoints для работы с permissions
💼 Use Case Layer
internal/usecase/permission/
CreatePermission, CheckAccess, Revoke, List, Update
🎯 Domain Layer
internal/domain/entity/permission.go + service/permission_service.go
Бизнес-логика, валидация, правила доступа
💾 Repository Layer
internal/repository/postgres/permission_repo.go
PostgreSQL реализация с custom функциями
🗄️ Database Layer
PostgreSQL с GIN индексами и оптимизированными функциями

Ключевые Компоненты

1. DocumentPermission Entity

Основная сущность, представляющая разрешение:

type DocumentPermission struct { ID uuid.UUID // Уникальный ID OwnerAppID uuid.UUID // Приложение-владелец SharedWithType SharedWithType // application/user/public SharedWithID string // ID получателя ScopeType ScopeType // document/path/level/query/all ScopeParams ScopeParams // Параметры scope PermissionLevel PermissionLevel // read/write/admin GrantedBy uuid.UUID // Кто выдал ExpiresAt *time.Time // Время истечения RevokedAt *time.Time // Время отзыва }

2. PermissionService

Domain service с бизнес-логикой:

// Проверка доступа к документу func (s *PermissionService) CheckAccess( ctx context.Context, subjectType SharedWithType, subjectID string, document *Document, requiredLevel PermissionLevel, ) (bool, PermissionLevel, *uuid.UUID, error) // Массовая фильтрация документов func (s *PermissionService) FilterAccessibleDocuments( ctx context.Context, subjectType SharedWithType, subjectID string, documents []Document, requiredLevel PermissionLevel, ) ([]Document, error)

🔐 Уровни Доступа

Permissions используют иерархическую модель, где более высокие уровни автоматически включают все возможности нижних уровней.

🔴 admin (3)
↓ включает ↓
🟡 write (2)
↓ включает ↓
🟢 read (1)
Уровень Значение Возможности Включает
read 1 Просмотр и скачивание документов
write 2 Создание, изменение, удаление документов read
admin 3 Все операции + управление разрешениями write, read
💡 Принцип: Максимальный Уровень Побеждает

Если у пользователя несколько permissions на один документ, система выбирает самый высокий уровень. Например: есть read на документ + admin на всё приложение = получает admin.

Примеры Проверки Уровней

Сценарий: Пользователь с write пытается получить доступ
Требуется read → write (2) ≥ read (1) → ✓ Доступ разрешен
Требуется write → write (2) ≥ write (2) → ✓ Доступ разрешен
Требуется admin → write (2) < admin (3) → ✗ Доступ запрещен

🎯 Типы Scope (Области Действия)

Scope определяет, на какие документы распространяется разрешение. Система поддерживает 5 типов scope от конкретного документа до всего приложения.

document 1. Конкретный Документ

Разрешение действует только на один конкретный документ.

Параметры:

{ "document_id": "uuid-документа" }

Когда использовать:

Поделиться конкретным контрактом с клиентом
Дать доступ к одному отчету
Создать публичную ссылку на файл
Пример: Документ "Contract-2024.pdf"
Документ с ID "doc-456" → ✓ Доступен
Документ с ID "doc-123" → ✗ Недоступен
Любые другие документы → ✗ Недоступны
hierarchy_path 2. Иерархический Путь

Разрешение действует на все документы в папке и вложенных папках.

Параметры:

{ "hierarchy_path": "/company1/department1/" }

Когда использовать:

Дать доступ ко всему отделу
Расшарить папку проекта
Организационный доступ по структуре
Пример: Путь "/projects/apollo/"
/projects/apollo/doc1.pdf → ✓ Доступен
/projects/apollo/team/doc2.pdf → ✓ Доступен (вложенный)
/projects/apollo/deep/nested/doc3.pdf → ✓ Доступен
/projects/other/doc.pdf → ✗ Недоступен
hierarchy_level 3. Уровень Иерархии

Разрешение действует на все документы на конкретной глубине иерархии.

Параметры:

{ "level": 2 // Уровень глубины }

Когда использовать:

Доступ ко всем документам "департаментов" (уровень 2)
Доступ к проектам (уровень 3)
Структурный доступ по глубине
Пример: Уровень 2
[org, dept] (2 элемента) → ✓ Доступен
[company, division] (2 элемента) → ✓ Доступен
[org] (1 элемент) → ✗ Недоступен
[org, dept, project] (3 элемента) → ✗ Недоступен
hierarchy_query 4. Запрос по Иерархии

Разрешение действует на документы, соответствующие фильтрам иерархии.

Параметры (3 варианта):

// Вариант 1: По ключу и значению { "key": "department", "value": "engineering" } // Вариант 2: Только ключ (любое значение) { "key": "project" } // Вариант 3: Сложные фильтры { "hierarchy_filters": [ {"key": "department", "id": "dept-uuid"}, {"key": "project", "id": "proj-uuid"} ] }

Когда использовать:

Все документы отдела "Engineering" (через разные организации)
Документы с тегом "проект:Apollo"
Кросс-секционный доступ по атрибутам
all 5. Все Документы

Разрешение действует на все документы приложения.

Параметры:

{} // Пустой объект

Когда использовать:

Полный доступ для админа
Расшаривание всех данных с другим приложением
Суперпользователь
⚠️ Осторожно

Scope "all" дает доступ ко ВСЕМ документам. Используйте с осторожностью и рассмотрите возможность добавления additional_filters для ограничения.

🔄 Флоу Проверки Доступа

Когда пользователь или приложение пытается получить доступ к документу, система проходит через 8 шагов для определения доступа.

📝 Пример: Пользователь хочет отредактировать документ
Запрос: user "john@company.com" → document "report.pdf" → level "write"
Шаг 1: HTTP Запрос
POST /api/v1/permissions/check-access
Входные данные: document_id, required_level, subject_type, subject_id
Шаг 2: Use Case - Валидация
CheckAccessUseCase.Execute()
✓ Проверка входных параметров
✓ Получение документа из БД
✓ Проверка, что документ не удален
Шаг 3: Domain Service
PermissionService.CheckAccess()
Вызов репозитория для проверки permissions
Шаг 4: Repository
CheckDocumentPermission()
Вызов PostgreSQL функции has_document_permission()
Шаг 5: PostgreSQL - Поиск и Проверка
5.1. Найти активные permissions для пользователя
5.2. Для каждого permission:
    ✓ Scope совпадает с документом?
    ✓ Уровень достаточный?
    ✓ Дополнительные фильтры совпадают?
5.3. Вернуть максимальный уровень
Шаг 6: Сравнение Уровней
granted_level >= required_level?
Пример: admin (3) >= write (2) → TRUE ✓
Шаг 7: Audit Log
Создание записи в permission_audit_log:
• Действие: access_granted / access_denied
• Детали: subject, document, level, IP, timestamp
Шаг 8: HTTP Ответ
200 OK
{ "has_access": true, "granted_level": "admin", "permission_id": "..." }
⚡ Производительность

Весь флоу проверки выполняется менее чем за 50ms даже при наличии 100+ permissions у пользователя. Оптимизация достигается через индексы PostgreSQL и единый запрос к БД.

🔌 Интеграция для Внешних Приложений

Эта секция объясняет, как именно внешнее приложение должно работать с API permissions: какие заголовки отправлять, как получить доступ, и как дать доступ другим.

✅ Гибкая Аутентификация

Оба метода аутентификации поддерживаются для всех операций:

1. JWT Tokens — для веб-интерфейса и пользовательских операций

2. API Keys — для API-to-API интеграции (рекомендуется для приложений)

Вы можете использовать API Key для управления permissions, создания документов и всех других операций!

Шаг 1: Регистрация и Получение Credentials

1.1. Регистрация Пользователя (Один раз)
POST /api/v1/auth/register Content-Type: application/json { "email": "admin@mycompany.com", "password": "SecurePassword123!", "full_name": "Admin User" } // Response: { "data": { "user": { "id": "user-uuid-123", "email": "admin@mycompany.com", "full_name": "Admin User" }, "access_token": "eyJhbGc...", "refresh_token": "refresh_..." } }
1.2. Создание Application (Получение API ключей)
POST /api/v1/applications Authorization: Bearer eyJhbGc... Content-Type: application/json { "name": "My App", "description": "Our main application" } // Response: { "data": { "id": "app-uuid-456", "name": "My App", "api_key_id": "clara_app_abc123", "api_key_secret": "secret_xyz789abc..." ⚠️ Сохраните! Показывается только один раз! } }
🔒 Сохраните API Secret!

api_key_secret показывается только при создании приложения. Сохраните его в безопасном месте (например, в переменных окружения). Если потеряете — нужно будет делать rotate keys.

Шаг 2: Использование API Keys для Работы с Документами

Формат API Key
// API Key в формате: {api_key_id}:{api_key_secret} // Пример: clara_app_abc123:secret_xyz789abc... // Отправляется в заголовке X-API-Key: X-API-Key: clara_app_abc123:secret_xyz789abc...
🎯 Автоматическая Фильтрация по Permissions

Используйте заголовок X-End-User-ID для автоматической фильтрации!

Когда ваше приложение работает от имени конкретного пользователя или группы, отправляйте дополнительный заголовок X-End-User-ID:

// Для конкретного пользователя: X-End-User-ID: john@company.com // Для группы пользователей: X-End-User-ID: group:engineering // Для роли: X-End-User-ID: role:admin // Для отдела: X-End-User-ID: department:sales

Как это работает:

Система автоматически проверяет permissions для этого пользователя/группы
При запросе списка документов, недоступные документы НЕ включаются в ответ
При запросе конкретного документа, возвращается 403 Forbidden если нет доступа
Вам НЕ нужно вручную проверять доступ — система делает это автоматически!
Пример 1: Запрос Списка (автоматическая фильтрация)
// Пользователь john@company.com запрашивает список документов POST /api/v1/documents/query X-API-Key: clara_app_abc123:secret_xyz789abc... X-End-User-ID: john@company.com ← Система автоматически отфильтрует по permissions Content-Type: application/json { "query_type": "raw", "limit": 20 } // Response: Только документы, к которым у john есть доступ! { "data": [ { "id": "doc-1", "name": "Contract.pdf" }, ← доступ есть { "id": "doc-3", "name": "Report.pdf" } ← доступ есть // doc-2 автоматически отфильтрован, т.к. у john нет permission ] }
Пример 2: Чтение Документа (с проверкой доступа)
GET /api/v1/documents/doc-uuid-456 X-API-Key: clara_app_abc123:secret_xyz789abc... X-End-User-ID: john@company.com // Если у john есть доступ → 200 OK { "data": { "id": "doc-uuid-456", "name": "Contract 2024.pdf", ... } } // Если у john нет доступа → 403 Forbidden { "error": { "code": "FORBIDDEN", "message": "Access denied" } }
Пример 3: Работа от имени Группы
// Запрос от группы "Engineering" POST /api/v1/documents/query X-API-Key: clara_app_abc123:secret_xyz789abc... X-End-User-ID: group:engineering ← Префикс "group:" для групп Content-Type: application/json { "query_type": "raw" } // Response: Документы, доступные группе engineering

Шаг 3: Управление Permissions (Дать Доступ Другим)

🔑 Два Способа Аутентификации

Способ 1 (рекомендуется для приложений): Используйте API Key

POST /api/v1/api/permissions X-API-Key: clara_app_abc123:secret_xyz789...

Способ 2 (для веб-интерфейса): Используйте JWT токен

POST /api/v1/permissions Authorization: Bearer eyJhbGc...

Оба способа работают одинаково. Для API-to-API интеграции используйте API Key (проще и безопаснее).

3.1. Дать Доступ Пользователю (используя API Key)
// Сценарий: Дать john@company.com доступ на чтение к документу POST /api/v1/api/permissions X-API-Key: clara_app_abc123:secret_xyz789... ← API Key вашего приложения Content-Type: application/json { "owner_app_id": "app-uuid-456", ← ID вашего приложения "shared_with_type": "user", ← Даем доступ пользователю "shared_with_id": "john@company.com", ← Email или external user ID "scope_type": "document", ← Конкретный документ "scope_params": { "document_id": "doc-uuid-789" }, "permission_level": "read", ← Уровень доступа "expires_at": "2024-12-31T23:59:59Z" ← Опционально: истекает через N дней } // Response: { "data": { "id": "perm-uuid", "owner_app_id": "app-uuid-456", "shared_with_type": "user", "shared_with_id": "john@company.com", "permission_level": "read", "created_at": "2024-11-19T..." } }
Теперь john@company.com может читать документ doc-uuid-789
John может получить доступ через свой API key (если у него есть приложение)
Или через публичную ссылку (если создали public permission)
3.2. Дать Доступ Другому Приложению (используя API Key)
// Сценарий: Приложение "Analytics" должно видеть все документы проекта "Apollo" POST /api/v1/api/permissions X-API-Key: clara_app_abc123:secret_xyz789... Content-Type: application/json { "owner_app_id": "my-app-uuid", ← Ваше приложение (владелец документов) "shared_with_type": "application", ← Даем доступ приложению "shared_with_id": "analytics-app-uuid", ← ID приложения-получателя "scope_type": "hierarchy_path", ← Вся папка "scope_params": { "hierarchy_path": "/projects/apollo/" ← Путь папки }, "permission_level": "read" ← Только чтение }
Теперь приложение Analytics может читать все документы в /projects/apollo/
Analytics использует свой API key для доступа к документам
Автоматически включает новые документы в этой папке
3.3. Дать Доступ Группе Пользователей (через hierarchy_query, используя API Key)
// Сценарий: Все пользователи отдела "Engineering" должны видеть технические документы POST /api/v1/api/permissions X-API-Key: clara_app_abc123:secret_xyz789... Content-Type: application/json { "owner_app_id": "my-app-uuid", "shared_with_type": "user", ← Тип: пользователь "shared_with_id": "group:engineering", ← Ваш идентификатор группы (prefix "group:") "scope_type": "hierarchy_query", ← Фильтр по иерархии "scope_params": { "key": "department", ← Ключ в иерархии "value": "engineering" ← Значение (ID отдела) }, "permission_level": "write", ← Могут редактировать "additional_filters": { "tags": ["technical", "internal"] ← Только с этими тегами } }
💡 Группы Пользователей

StoreApp не управляет группами напрямую. Вы определяете группы в своем приложении и передаете идентификатор группы в shared_with_id. Проверка membership происходит на вашей стороне.

3.4. Создать Публичную Ссылку (используя API Key)
// Сценарий: Создать публичную ссылку на отчет, действительную 7 дней // Шаг 1: Генерация токена (на вашей стороне) const token = "pub_" + generateRandomString(32) // pub_a1b2c3d4e5... // Шаг 2: Создание permission POST /api/v1/api/permissions X-API-Key: clara_app_abc123:secret_xyz789... Content-Type: application/json { "owner_app_id": "my-app-uuid", "shared_with_type": "public", ← Публичный доступ "shared_with_id": "pub_a1b2c3d4e5...", ← Сгенерированный токен "scope_type": "document", "scope_params": { "document_id": "report-uuid" }, "permission_level": "read", "expires_at": "2024-11-26T23:59:59Z" ← Истекает через 7 дней } // Шаг 3: Возвращаете пользователю ссылку const publicUrl = `https://storage.myapp.com/public/${token}/documents/${documentId}`
Использование Публичной Ссылки (без аутентификации!)
// Любой может получить доступ БЕЗ логина: GET /api/v1/public/{token}/documents/{document-id} // НЕТ заголовков аутентификации! // Response: { "data": { "id": "report-uuid", "name": "Report.pdf", "download_url": "/api/v1/public/{token}/documents/{id}/download" } }
Любой с токеном может просмотреть документ
Не требуется логин или API key
Ссылка автоматически перестает работать после expires_at
Все обращения логируются в audit_log с IP адресом

Шаг 4: Проверка Доступа

Как Проверить, Есть ли у Пользователя Доступ (используя API Key)
POST /api/v1/api/permissions/check-access X-API-Key: clara_app_abc123:secret_xyz789... Content-Type: application/json { "document_id": "doc-uuid", "subject_type": "user", ← user / application / public "subject_id": "john@company.com", ← ID пользователя/приложения/токена "required_level": "write" ← Требуемый уровень } // Response: Доступ есть { "data": { "has_access": true, "granted_level": "admin", ← У пользователя даже выше уровень "permission_id": "perm-uuid" } } // Response: Доступа нет { "data": { "has_access": false, "granted_level": "", "permission_id": null } }

Шаг 5: Отзыв Доступа

Отозвать Permission (используя API Key)
DELETE /api/v1/api/permissions/{permission-id} X-API-Key: clara_app_abc123:secret_xyz789... // Response: { "data": { "message": "Permission revoked successfully" } }
Permission помечается как отозванный (revoked_at)
Пользователь сразу теряет доступ
Запись остается в БД для audit

Полный Пример: Интеграция в Ваше Приложение (только API Key)

// ===== 1. Инициализация (один раз через веб или CLI) ===== // Шаг 1: Зарегистрируйтесь через веб-интерфейс или API // POST /api/v1/auth/register // Шаг 2: Создайте приложение (через веб или JWT) // POST /api/v1/applications (требует JWT от шага 1) // Получите API_KEY_ID и API_KEY_SECRET // Шаг 3: Сохраните credentials в .env: // API_KEY_ID=clara_app_abc123 // API_KEY_SECRET=secret_xyz789... // APP_ID=app-uuid-456 // ===== 2. В вашем приложении (используем только API Key) ===== const apiKey = `${process.env.API_KEY_ID}:${process.env.API_KEY_SECRET}` const appId = process.env.APP_ID // ===== 3. Загрузка документа ===== const document = await fetch('http://localhost:3100/api/v1/documents', { method: 'POST', headers: { 'X-API-Key': apiKey, }, body: formData // multipart/form-data с file, name, hierarchy }).then(r => r.json()) // ===== 4. Дать доступ клиенту (используя API Key!) ===== await fetch('http://localhost:3100/api/v1/api/permissions', { method: 'POST', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json', }, body: JSON.stringify({ owner_app_id: appId, shared_with_type: 'user', shared_with_id: 'client@acme.com', scope_type: 'document', scope_params: { document_id: document.data.id }, permission_level: 'read' }) }) // ===== 5. Проверка доступа перед операцией ===== const accessCheck = await fetch('http://localhost:3100/api/v1/api/permissions/check-access', { method: 'POST', headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json', }, body: JSON.stringify({ document_id: document.data.id, subject_type: 'user', subject_id: 'client@acme.com', required_level: 'read' }) }).then(r => r.json()) if (accessCheck.data.has_access) { // Разрешаем операцию } else { // Возвращаем 403 Forbidden }
✅ Готово!

Теперь вы знаете, как интегрировать permissions в ваше приложение. Используйте API Key для всех операций (документы + permissions) — это проще и удобнее для API-to-API интеграции!

📝 Сводная Таблица Endpoints
Операция JWT Endpoint API Key Endpoint
Создать permission POST /api/v1/permissions POST /api/v1/api/permissions
Список permissions GET /api/v1/permissions GET /api/v1/api/permissions
Получить permission GET /api/v1/permissions/{id} GET /api/v1/api/permissions/{id}
Обновить permission PUT /api/v1/permissions/{id} PUT /api/v1/api/permissions/{id}
Удалить permission DELETE /api/v1/permissions/{id} DELETE /api/v1/api/permissions/{id}
Проверить доступ POST /api/v1/permissions/check-access POST /api/v1/api/permissions/check-access
Создать публичную ссылку POST /api/v1/permissions/generate-public-link POST /api/v1/api/permissions/generate-public-link

Рекомендация: Используйте API Key endpoints (/api/v1/api/*) для приложений. JWT endpoints (/api/v1/*) предназначены для веб-интерфейса.

💡 Практические Примеры

Пример 1: Поделиться Документом с Пользователем

Задача: Дать пользователю john@company.com доступ на чтение к контракту

HTTP Запрос:

POST /api/v1/permissions Authorization: Bearer {jwt_token} { "owner_app_id": "app-uuid-123", "shared_with_type": "user", "shared_with_id": "john@company.com", "scope_type": "document", "scope_params": { "document_id": "contract-uuid" }, "permission_level": "read" }

Результат:

Пользователь может просматривать и скачивать контракт
НЕ может редактировать или удалять
НЕ имеет доступа к другим документам

Пример 2: Публичная Ссылка с Истечением

Задача: Создать публичную ссылку на отчет, действительную 7 дней
const token = "pub_" + generateRandomToken() // pub_a1b2c3d4e5... const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) POST /api/v1/permissions { "owner_app_id": "app-uuid", "shared_with_type": "public", "shared_with_id": token, "scope_type": "document", "scope_params": { "document_id": "report-uuid" }, "permission_level": "read", "expires_at": expiresAt }

Публичная ссылка:

https://storage.company.com/public/pub_a1b2c3d4e5.../documents/report-uuid

Результат:

Любой с ссылкой может просмотреть отчет (без логина)
Ссылка автоматически истекает через 7 дней
Все обращения логируются с IP адресом

Пример 3: Доступ к Папке Проекта

Задача: Дать приложению аналитики доступ ко всем документам проекта Apollo
POST /api/v1/permissions { "owner_app_id": "my-app-uuid", "shared_with_type": "application", "shared_with_id": "analytics-app-uuid", "scope_type": "hierarchy_path", "scope_params": { "hierarchy_path": "/projects/apollo/" }, "permission_level": "read" }

Результат:

Аналитика может читать ВСЕ документы в /projects/apollo/
Включая вложенные папки: /projects/apollo/docs/, /projects/apollo/images/
Автоматически включает новые документы в папке
НЕ имеет доступа к /projects/other-project/

Пример 4: Фильтр по Типу Файла и Тегам

Задача: Поделиться только PDF-счетами за Q4 с бухгалтерией
POST /api/v1/permissions { "owner_app_id": "my-app", "shared_with_type": "application", "shared_with_id": "accounting-app", "scope_type": "all", "scope_params": {}, "permission_level": "read", "additional_filters": { "mime_types": ["application/pdf"], "tags": ["invoice"], "created_after": "2024-10-01T00:00:00Z", "created_before": "2024-12-31T23:59:59Z" } }

Результат:

Доступ только к PDF файлам
Только с тегом "invoice"
Только созданным в Q4 2024
Все фильтры должны совпадать (AND логика)

⚡ Производительность

Одиночная Проверка Доступа

Permissions у Пользователя Время Проверки Примечание
1-10 < 5ms Одиночный индексный lookup
10-100 < 10ms Проверка нескольких scope
100-1000 < 50ms Сложные hierarchy query
1000+ < 100ms Full table scan (редко)

Массовая Фильтрация Документов

Документов Permissions Время Примечание
100 10 < 50ms Один батч-запрос
1,000 100 < 200ms Эффективный IN clause
10,000 1,000 < 500ms Рекомендуемый размер
100,000 10,000 < 5s Максимальный батч
🚀 Оптимизации
  • PostgreSQL функции минимизируют round-trips
  • GIN индексы на JSONB для быстрого поиска
  • Составные индексы на (shared_with_type, shared_with_id)
  • Batch обработка до 100K документов
  • Нет N+1 queries благодаря единому SQL запросу

Рекомендации по Производительности

Используйте наиболее специфичный scope для минимизации проверок
Батчи по 10K документов для лучшего отклика
Избегайте слишком сложных additional_filters
Регулярно очищайте истекшие permissions
Мониторьте количество permissions у пользователей (оптимально < 100)

✅ Тестирование

Система permissions покрыта 97+ комплексными тестами, обеспечивающими надежность и правильность работы во всех сценариях.

25
Entity Tests
29
Service Tests
43
Use Case Tests
40+
Integration Tests

Что Протестировано

Все 3 уровня доступа (read, write, admin) + наследование
Все 5 типов scope с различными параметрами
Все 3 типа shared_with (application, user, public)
Все дополнительные фильтры и их комбинации
Состояния: активные, истекшие, отозванные permissions
Бизнес-логика: валидация, проверка доступа, массовая фильтрация
Обработка ошибок: невалидные данные, ошибки БД, edge cases
Audit logging для всех операций
🎯 Production Ready

Система прошла полное тестирование и готова к использованию в продакшене. Покрытие ~85% гарантирует надежность в реальных условиях.

Запуск Тестов

# Unit тесты (без БД) go test ./internal/domain/entity/ -run TestPermission -v go test ./internal/domain/service/ -v go test ./internal/usecase/permission/ -v # Integration тесты (требуется БД) export TEST_DATABASE_URL='postgresql://...' go test -tags=integration ./internal/repository/postgres/ -run TestPermission -v # С race detector go test -race ./internal/domain/... ./internal/usecase/permission/

📚 Дополнительные Ресурсы

PERMISSIONS_HOW_IT_WORKS.md

Детальное руководство на английском с примерами кода и схемами

PERMISSIONS_FLOW_RU.md

Пошаговое описание всех флоу на русском языке

HIERARCHICAL_PERMISSIONS_SYSTEM.md

Полная документация системы (1400+ строк, русский)

PERMISSIONS_API_GUIDE.md

Документация API endpoints для работы с permissions

🎉 Готово к Использованию

Система permissions полностью реализована, протестирована и задокументирована. Используйте примеры выше для интеграции в ваше приложение. При возникновении вопросов обращайтесь к документации или проверяйте audit logs для диагностики.