Установка API
Установка серверной части — последовательность: подключить приватные репозитории, поставить пакет, опубликовать файлы Frame, прописать окружение и запустить миграции.
Подключите репозитории Frame
Добавьте репозитории Frame в composer.json:
{
"repositories": {
"frame": {
"type": "composer",
"url": "https://git.qubeek.io/api/v4/group/55/-/packages/composer/packages.json"
},
"qubeekio": {
"type": "composer",
"url": "https://git.qubeek.io/api/v4/group/138/-/packages/composer/packages.json"
}
}
}
Добавьте зависимость:
{
"require": {
"frame/frame": "^0.2.0"
}
}
"frame/frame": "*" если хотите всегда получать последнюю версию.Настройте авторизацию Composer
Репозитории приватные — Composer отдельно нужен токен. Создайте auth.json рядом с composer.json:
{
"gitlab-domains": ["git.qubeek.io"],
"gitlab-token": {
"git.qubeek.io": "<ваш-токен>"
}
}
auth.json в .gitignore — файл содержит секрет. Токен выдаётся службой поддержки.Проверьте платформенные требования
Frame (через phpoffice/phpspreadsheet) требует PHP-расширение ext-gd. Убедитесь, что оно установлено:
php -m | grep -i gd
Если расширение отсутствует, добавьте в Dockerfile/окружение, либо разово установите с игнорированием проверки:
composer update --ignore-platform-req=ext-gd
frame/frame также фиксирует giggsey/libphonenumber-for-php ^8.13. Если в вашем проекте уже установлена 9-я ветка — потребуется временное понижение или координация с апстримом.Пропишите переменные окружения
Добавьте в .env:
panel.example.com.example.com,panel.example.com.example.com, панель на panel.example.com) значение должно начинаться с точки: .example.com.Установите зависимости
composer update --with-all-dependencies
Флаг -W (--with-all-dependencies) нужен, потому что установка frame/frame может затрагивать уже заблокированные корневые пакеты (Laravel, Sanctum, nesbot/carbon и др.).
Опубликуйте файлы Frame
php artisan frame:install

php artisan frame:publish

Зарегистрируйте сервис-провайдер
frame:install создаёт app/Providers/FrameServiceProvider.php, но не прописывает его в bootstrap/providers.php. Добавьте вручную:
use App\Providers\FrameServiceProvider;
return [
AppServiceProvider::class,
FrameServiceProvider::class,
// ...
];
Без этого биндинги (DefinesPermissions, дашборды, глобальная конфигурация Frame) не будут применяться.
Настройте путь панели
По умолчанию опубликованный config/frame.php использует web.path = '/frame'. Если панель живёт на отдельном домене (FRAME_DOMAIN_NAME), откройте её на корне:
'web' => [
'path' => '/',
'middleware' => [],
],
Запустите миграции
php artisan migrate
Миграции Frame (таблицы frame_*) подгружаются автоматически из вендора.
Настройте поисковый движок (опционально)
По умолчанию глобальный поиск работает через TNTSearch — файловый индекс в storage/frame/frame_global_index. Индекс автоматически создаётся и обновляется, но на больших объёмах заметно проигрывает специализированным движкам по качеству выдачи и скорости.
Для продакшена рекомендуется Meilisearch. Подключение:
- Добавьте сервис в
docker-compose.yml:
services:
meilisearch:
image: getmeili/meilisearch:v1.14
ports:
- '7700:7700'
environment:
- MEILI_MASTER_KEY=${MEILISEARCH_KEY:-masterKey}
- MEILI_NO_ANALYTICS=true
- MEILI_ENV=development
volumes:
- 'meilisearch-storage:/meili_data'
volumes:
meilisearch-storage:
- Установите PHP-клиент:
composer require meilisearch/meilisearch-php:^1.15
- Пропишите в
.env:
MEILISEARCH_HOST=http://meilisearch:7700
MEILISEARCH_KEY=masterKey
- Переключите драйвер в
config/frame.php:
use Frame\Laravel\Search\MeilisearchDriver;
'global_search' => [
'driver' => MeilisearchDriver::class,
// ...
],
- Создайте индекс и перенесите данные:
php artisan frame:create-meilisearch-index
php artisan frame:import-resources
Если до этого использовался TNTSearch — удалите папку storage/frame/frame_global_index и добавьте /storage/frame в .gitignore, чтобы артефакты индекса не попадали в репозиторий.
frame:create-algolia-index) и Typesense (frame:create-typesense-index). Драйверы называются AlgoliaDriver/TypesenseDriver в Frame\Laravel\Search\*.Проверьте entry.blade.php
После публикации откройте resources/views/vendor/frame/entry.blade.php. Критично наличие директивы @frameAssets — она регистрируется в FrameServiceProvider и подключает Vite-теги фронтенд-бандла (dev-сервер с HMR или продакшен-сборку из каталога frame). Без неё фронтенд не подключится, а страница отрисуется как пустой <div id="app"> без ошибок в консоли. Если директива отсутствует, замените содержимое файла:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="UTF-8">
@if($favicon)
<link rel="icon" href="{{ $favicon }}">
@endif
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="Qubeek.io">
<meta name="robots" content="noindex, nofollow, noarchive, nosnippet, noimageindex">
<meta name="googlebot" content="noindex, nofollow">
<meta name="format-detection" content="telephone=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="X-Content-Type-Options" content="nosniff">
<meta http-equiv="X-XSS-Protection" content="1; mode=block">
@if(app()->environment('production'))
<meta http-equiv="X-Frame-Options" content="DENY">
@endif
<title>{{ $app_name }}</title>
<script type="text/javascript">
window.Frame = {
config: @json($__data)
}
</script>
@frameAssets
</head>
<body>
<div id="app"></div>
</body>
</html>
Настройте nginx (опционально)
Если панель доступна на отдельном домене, настройте проксирование:
server {
listen 80;
server_name panel.you-domain.com;
charset utf-8;
client_max_body_size 1024M;
location / {
proxy_pass http://api:80;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /api-storage {
alias /var/www/html/api-storage;
try_files $uri $uri/ =404;
}
}
Что дальше
- Конфигурация приложения — название, логотип, пути, локали через PHP/JS
- Профиль пользователя — если у вашей
User-модели поля называются неname/surname/email/avatar - Модули — подключение
frame/permissions,frame/notes,frame/action-events - Драйверы медиа — файлы и изображения