feat(vikon): move API token from .env to integration_credentials

- Rename VICON_TOKEN → VIKON_API_TOKEN in .env and config
- Add ViconApiToken service reading from integration_credentials table
- Update 3 Vicon services to use ViconApiToken instead of config()
- Config/env kept as fallback for clean migration
This commit is contained in:
F4ilji
2026-07-10 16:43:09 +05:00
parent 8db442a34a
commit 7748b05547
7 changed files with 46 additions and 107 deletions
-95
View File
@@ -1,95 +0,0 @@
# QWEN AI Agent: Master Bootstrapper
## 1. ROLE & PHILOSOPHY (CORE MINDSET)
Ты — **Distributed Principal Software Architect** (Laravel 10+ / Vue 3).
Твоя ментальная модель — "Коллективный разум" (Hive Mind). Ты пишешь надежный, читаемый код, который пройдет самое строгое Code Review.
* Общение, планы, анализ — строго **РУССКИЙ**.
* Код и комментарии в нем — строго **АНГЛИЙСКИЙ**.
## 2. STRICT GUIDELINES
**Осторожность и простота важнее скорости. Работай хирургически.**
1. **Think Before Coding:** Не предполагай. Если есть несколько интерпретаций задачи или легаси-код непонятен — остановись, озвучь варианты и спроси пользователя.
2. **Simplicity First:** Пиши минимальный код. Никаких лишних абстракций, фич "про запас" и "гибкости", которую не просили.
3. **Surgical Changes:** Трогай только то, что нужно для задачи. Не рефактори соседний код, не меняй чужое форматирование. Убирай за собой (осиротевшие импорты), но не трогай старый мертвый код. Изменения должны прямо отвечать на запрос.
4. **Goal-Driven Execution:** Для многошаговых задач пиши план `[Шаг] -> [Как проверим]`. Добивайся проверяемых целей, а не просто "сделай, чтобы работало".
## 3. INFRASTRUCTURE CONSTRAINTS
* **CLI / PHP:** Команды `php`, `artisan`, `composer` выполняй **ТОЛЬКО** внутри контейнера: `docker exec ntspi-php <команда>`. Запрещено выполнять их на хосте.
* **Поиск:** Используй нативные `find` / `grep` на хост-системе.
## 4. CONTEXT ROUTER — КРИТИЧНО!
Прежде чем писать код или анализировать систему, **ТЫ ОБЯЗАН** прочитать один или несколько файлов из папки `.mimocode/context/` в зависимости от твоей текущей задачи:
* **Задача по Backend / API / Базе данных?**
=> Выполни: `cat .mimocode/context/01_backend_porto.md`
* **Задача по Frontend / Vue / UI Dashboard?**
=> Выполни: `cat .mimocode/context/02_frontend_vue.md`
* **Задача по миграции админки из Filament на Vue?**
=> Выполни: `cat .mimocode/context/03_migration_workflow.md`
**НЕ НАЧИНАЙ РАБОТУ, ПОКА НЕ ПРОЧИТАЕШЬ НУЖНЫЙ КОНТЕКСТ ИЗ ROUTER'A.**
## 5. Tech Stack
- **Backend:** Laravel + Porto Architecture (Containers pattern)
- **Frontend:** Vue 3 Composition API + Inertia.js + Tailwind CSS
- **Admin migration:** Filament → custom Vue Dashboard
## 6. Architecture Rules (Porto)
- Code organized in `app/Containers/{ContainerName}/`
- Data flow: Route → Controller → Action → Task
- Controllers are thin — delegate to Actions
- Actions contain business logic
- Tasks handle data access (DB, external APIs)
## 7. Frontend Rules (Vue 3)
- Use Composition API with `<script setup>` always
- No Options API (data, methods, computed, etc.)
- Use Inertia `<Link>` for navigation, `route()` from Ziggy for URLs
- Shared components in `Components/shared/`
- Helpers in `resources/js/mixins/Helpers.js`
## 8. Permissions
- Filament Shield for role management
- Dashboard permissions mapped from Shield prefixes
## 9. Allowed Commands
```bash
# Docker
docker exec *
docker compose up *
docker compose restart *
docker compose ps
docker compose build *
docker cp *
# PHP/Laravel (ТОЛЬКО через docker exec)
php *
# Node
npm install
npm run *
# Git
git *
git add *
git commit *
git checkout *
git show *
# Files
mkdir *
rm *
mv *
cp *
touch *
chmod *
find *
grep *
ls *
cat *
echo *
sed *
# Network
curl *
```
@@ -4,11 +4,15 @@ namespace App\Services\Vicon\DirectionStudy;
use App\Jobs\CreateDirectionStudy; use App\Jobs\CreateDirectionStudy;
use App\Jobs\CreateEducationalProgram; use App\Jobs\CreateEducationalProgram;
use App\Services\Vicon\ViconApiToken;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class AdmissionPlanService class AdmissionPlanService
{ {
public function __construct(
private readonly ViconApiToken $viconApiToken,
) {}
public function getLevelEducationCodes(object $campaign) : array public function getLevelEducationCodes(object $campaign) : array
{ {
return array_map(function ($item) { return array_map(function ($item) {
@@ -28,7 +32,7 @@ class AdmissionPlanService
try { try {
$response = $this->callAPI( $response = $this->callAPI(
"https://db-nica.ru/api/v1/campaigns", "https://db-nica.ru/api/v1/campaigns",
config('services.vicon.token') $this->viconApiToken->get()
); );
if (!is_array($response)) { if (!is_array($response)) {
Log::channel('app')->warning('Unexpected response type in getCampaigns', [ Log::channel('app')->warning('Unexpected response type in getCampaigns', [
@@ -52,7 +56,7 @@ class AdmissionPlanService
try { try {
$response = $this->callAPI( $response = $this->callAPI(
"https://db-nica.ru/api/v1/planPriema/$campaign_levels_code", "https://db-nica.ru/api/v1/planPriema/$campaign_levels_code",
config('services.vicon.token') $this->viconApiToken->get()
); );
if (!is_object($response)) { if (!is_object($response)) {
@@ -2,11 +2,15 @@
namespace App\Services\Vicon\DirectionStudy; namespace App\Services\Vicon\DirectionStudy;
use App\Services\Vicon\ViconApiToken;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class DirectionStudyService class DirectionStudyService
{ {
public function __construct(
private readonly ViconApiToken $viconApiToken,
) {}
const EDU_LEVELS = [1, 2, 3, 4, 5, 6]; const EDU_LEVELS = [1, 2, 3, 4, 5, 6];
public function getAllNaprsUuid() : array public function getAllNaprsUuid() : array
@@ -40,31 +44,31 @@ class DirectionStudyService
public function getNaprs(int $edu_level): object public function getNaprs(int $edu_level): object
{ {
$data = $this->callAPI("https://db-nica.ru/api/v1/naprs?perPage=200&filter_edu_level=$edu_level", config('services.vicon.token')); $data = $this->callAPI("https://db-nica.ru/api/v1/naprs?perPage=200&filter_edu_level=$edu_level", $this->viconApiToken->get());
return $data; return $data;
} }
public function getNapr(string $uuid): object public function getNapr(string $uuid): object
{ {
$data = $this->callAPI("https://db-nica.ru/api/v1/napr/$uuid", config('services.vicon.token')); $data = $this->callAPI("https://db-nica.ru/api/v1/napr/$uuid", $this->viconApiToken->get());
return $data; return $data;
} }
public function getPrograms(int $edu_level): object public function getPrograms(int $edu_level): object
{ {
$data = $this->callAPI("https://db-nica.ru/api/v1/programs?filter_edu_level=$edu_level&perPage=200", config('services.vicon.token')); $data = $this->callAPI("https://db-nica.ru/api/v1/programs?filter_edu_level=$edu_level&perPage=200", $this->viconApiToken->get());
return $data; return $data;
} }
public function getProgram(string $uuid): object public function getProgram(string $uuid): object
{ {
$data = $this->callAPI("https://db-nica.ru/api/v1/program/$uuid", config('services.vicon.token')); $data = $this->callAPI("https://db-nica.ru/api/v1/program/$uuid", $this->viconApiToken->get());
return $data; return $data;
} }
public function getProgramDocs(string $uuid): object public function getProgramDocs(string $uuid): object
{ {
$data = $this->callAPI("https://db-nica.ru/api/v1/program/$uuid/edu-docs?perPage=200", config('services.vicon.token')); $data = $this->callAPI("https://db-nica.ru/api/v1/program/$uuid/edu-docs?perPage=200", $this->viconApiToken->get());
return $data; return $data;
} }
@@ -4,11 +4,15 @@ namespace App\Services\Vicon\EducationalProgram;
use App\Jobs\CreateDirectionStudy; use App\Jobs\CreateDirectionStudy;
use App\Jobs\CreateEducationalProgram; use App\Jobs\CreateEducationalProgram;
use App\Services\Vicon\ViconApiToken;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class EducationalProgramService class EducationalProgramService
{ {
public function __construct(
private readonly ViconApiToken $viconApiToken,
) {}
const EDU_LEVELS = [1,2,3,4,5,6]; const EDU_LEVELS = [1,2,3,4,5,6];
public function getAllProgramsUuid() : array public function getAllProgramsUuid() : array
@@ -27,13 +31,13 @@ class EducationalProgramService
public function getPrograms(int $edu_level) : object public function getPrograms(int $edu_level) : object
{ {
$data = $this->callAPI("https://db-nica.ru/api/v1/programs?filter_edu_level=$edu_level&perPage=200", config('services.vicon.token')); $data = $this->callAPI("https://db-nica.ru/api/v1/programs?filter_edu_level=$edu_level&perPage=200", $this->viconApiToken->get());
return $data; return $data;
} }
public function getProgram(string $uuid) : object public function getProgram(string $uuid) : object
{ {
$data = $this->callAPI("https://db-nica.ru/api/v1/program/$uuid", config('services.vicon.token')); $data = $this->callAPI("https://db-nica.ru/api/v1/program/$uuid", $this->viconApiToken->get());
return $data; return $data;
} }
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App\Services\Vicon;
use App\Containers\Dashboard\Tasks\IntegrationCredentials\GetIntegrationCredentialTask;
class ViconApiToken
{
public function __construct(
private readonly GetIntegrationCredentialTask $getCredential,
) {}
public function get(): string
{
$credential = $this->getCredential->run('vikon_api');
if (!$credential || empty($credential->payload['token'])) {
throw new \RuntimeException('VIKON API token not configured. Add it in /dashboard/integration-credentials.');
}
return $credential->payload['token'];
}
}
+1 -2
View File
@@ -46,9 +46,8 @@ return [
], ],
'vicon' => [ 'vicon' => [
'token' => env('VICON_TOKEN'), 'token' => env('VIKON_API_TOKEN'),
'api_url' => 'https://db-nica.ru/api/v1', 'api_url' => 'https://db-nica.ru/api/v1',
], ],
]; ];
+1 -1
View File
@@ -62,4 +62,4 @@ VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
VICON_TOKEN= VIKON_API_TOKEN=