Compare commits
4 Commits
ab89913ebf
...
5e68f7dd64
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e68f7dd64 | |||
| 4857be3d41 | |||
| 2bbbdc0262 | |||
| ce5a85628c |
@@ -1,14 +0,0 @@
|
|||||||
# Pinecore Knowledge Base
|
|
||||||
|
|
||||||
Детальная документация по реализации. См. также [CLAUDE.md](../CLAUDE.md) для базового обзора.
|
|
||||||
|
|
||||||
## Разделы
|
|
||||||
|
|
||||||
- [Архитектура и жизненный цикл запроса](kb/architecture.md)
|
|
||||||
- [Ядро, Config, Environment, ContainerFactory](kb/bootstrap.md)
|
|
||||||
- [HTTP слой](kb/http.md)
|
|
||||||
- [Worker и запуск](kb/worker.md)
|
|
||||||
- [Аутентификация (JWT)](kb/auth.md)
|
|
||||||
- [Логирование](kb/logging.md)
|
|
||||||
- [ORM (MongoDB)](kb/orm.md)
|
|
||||||
- [Console](kb/console.md)
|
|
||||||
62
.claude/README.md
Normal file
62
.claude/README.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# Knowledge Base Index
|
||||||
|
|
||||||
|
Полный индекс базы знаний проекта Pinecore. Все файлы в этой директории коммитятся в репозиторий.
|
||||||
|
|
||||||
|
## Быстрая навигация
|
||||||
|
|
||||||
|
| Что нужно | Файл |
|
||||||
|
|-----------|------|
|
||||||
|
| Я только что открыл проект | [`architecture/overview.md`](architecture/overview.md) |
|
||||||
|
| Как поднять worker / запустить? | [`development/commands.md`](development/commands.md) |
|
||||||
|
| Какой паттерн использовать? | [`development/patterns.md`](development/patterns.md) |
|
||||||
|
| Commit/branch/namespace conventions | [`development/conventions.md`](development/conventions.md) |
|
||||||
|
| Как отладить локально | [`development/testing.md`](development/testing.md) |
|
||||||
|
| Ядро, Config, Environment, ContainerFactory | [`architecture/bootstrap.md`](architecture/bootstrap.md) |
|
||||||
|
| HTTP: Request, Response, Router, Middleware | [`architecture/http.md`](architecture/http.md) |
|
||||||
|
| Worker и WorkerRunner | [`architecture/worker.md`](architecture/worker.md) |
|
||||||
|
| Auth (JWT, AuthMiddleware) | [`architecture/auth.md`](architecture/auth.md) |
|
||||||
|
| Логирование | [`architecture/logging.md`](architecture/logging.md) |
|
||||||
|
| ORM (MongoDB) | [`architecture/orm.md`](architecture/orm.md) |
|
||||||
|
| Console-команды | [`architecture/console.md`](architecture/console.md) |
|
||||||
|
| Почему архитектура именно такая | [`decisions/README.md`](decisions/README.md) |
|
||||||
|
| Контекст текущей задачи | [`tasks/active/`](tasks/active/) |
|
||||||
|
|
||||||
|
## Структура директории
|
||||||
|
|
||||||
|
```
|
||||||
|
.claude/
|
||||||
|
├── README.md # Этот файл — индекс
|
||||||
|
├── architecture/ # Стабильные архитектурные docs
|
||||||
|
│ ├── overview.md # Обзор системы и жизненный цикл запроса
|
||||||
|
│ ├── bootstrap.md # Kernel, Config, Environment, ContainerFactory
|
||||||
|
│ ├── http.md # HTTP слой: Request, Response, Router, Middleware
|
||||||
|
│ ├── worker.md # Worker entrypoint и WorkerRunner
|
||||||
|
│ ├── auth.md # Auth: JWT, AuthMiddleware
|
||||||
|
│ ├── logging.md # Логирование
|
||||||
|
│ ├── orm.md # ORM: MongoDB, entities, repositories
|
||||||
|
│ └── console.md # Console-команды
|
||||||
|
├── development/ # Практика разработки
|
||||||
|
│ ├── patterns.md # Переиспользуемые code patterns
|
||||||
|
│ ├── conventions.md # Соглашения: коммиты, ветки, неймспейсы
|
||||||
|
│ ├── commands.md # Команды запуска и утилиты
|
||||||
|
│ └── testing.md # Отладка и тестирование
|
||||||
|
├── decisions/ # Architecture Decision Records (ADR)
|
||||||
|
│ ├── README.md # Индекс ADR + как писать
|
||||||
|
│ └── ADR-NNN-*.md
|
||||||
|
└── tasks/ # Контекст задач (по одному файлу на ветку)
|
||||||
|
├── _template.md # Шаблон для новой задачи
|
||||||
|
├── active/ # Активные ветки
|
||||||
|
└── completed/ # Смерженные задачи
|
||||||
|
```
|
||||||
|
|
||||||
|
## Правила обновления
|
||||||
|
|
||||||
|
**Во время разработки в feature-ветке:**
|
||||||
|
- Пиши только в `tasks/active/<branch-name>.md` (свой файл)
|
||||||
|
- Можешь добавить `decisions/ADR-NNN.md` (новый файл — нет конфликтов)
|
||||||
|
- НЕ трогай `architecture/` и `development/` — только в main
|
||||||
|
|
||||||
|
**После мержа в main (интегратор):**
|
||||||
|
- Читает секцию "Merge Notes" в task-файле
|
||||||
|
- При необходимости обновляет `architecture/` и `development/`
|
||||||
|
- Перемещает: `tasks/active/<branch>.md` → `tasks/completed/<branch>.md`
|
||||||
@@ -41,16 +41,27 @@ ContainerFactory::build(Environment $env, Config $config, string $basePath): Con
|
|||||||
|
|
||||||
- Autowiring включён всегда
|
- Autowiring включён всегда
|
||||||
- В prod: `$builder->enableCompilation($basePath . '/var/cache/prod/')`
|
- В prod: `$builder->enableCompilation($basePath . '/var/cache/prod/')`
|
||||||
- Загружает `$basePath/config/services.php` — файл должен вернуть `callable($builder, $config, $basePath)`
|
- Загружает `$basePath/config/routes.php` (если есть) — файл возвращает `RouteDefinition[]`,
|
||||||
|
фреймворк автоматически создаёт `Router` и регистрирует его в контейнере
|
||||||
|
- Загружает `$basePath/config/services.php` (если есть) — файл возвращает
|
||||||
|
`callable($builder, $config, $basePath)`; загружается после routes.php и может переопределить
|
||||||
|
любые определения, включая `Router::class`
|
||||||
|
|
||||||
**Пример `config/services.php`:**
|
**`config/routes.php`** (конвенция, предпочтительный способ):
|
||||||
|
```php
|
||||||
|
use Pronchev\Pinecore\Http\RouteDefinition;
|
||||||
|
|
||||||
|
return [
|
||||||
|
new RouteDefinition('GET', '/users/{id}', GetUserController::class, [AuthMiddleware::class]),
|
||||||
|
new RouteDefinition('POST', '/users', CreateUserController::class, [AuthMiddleware::class]),
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
**`config/services.php`** (для DI-биндингов и переопределений):
|
||||||
```php
|
```php
|
||||||
return function (ContainerBuilder $builder, Config $config, string $basePath): void {
|
return function (ContainerBuilder $builder, Config $config, string $basePath): void {
|
||||||
$builder->addDefinitions([
|
$builder->addDefinitions([
|
||||||
UserProviderInterface::class => fn($c) => $c->get(UserRepository::class),
|
UserProviderInterface::class => fn($c) => $c->get(UserRepository::class),
|
||||||
Router::class => fn() => new Router([
|
|
||||||
new RouteDefinition('GET', '/users/{id}', GetUserController::class, [AuthMiddleware::class]),
|
|
||||||
]),
|
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
@@ -68,3 +68,21 @@ $response->emit(): void // http_response_code + headers + e
|
|||||||
throw new HttpException('Forbidden', 403);
|
throw new HttpException('Forbidden', 403);
|
||||||
// → перехватывается в HttpApplication::dispatch() → Response::error(message, code)
|
// → перехватывается в HttpApplication::dispatch() → Response::error(message, code)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## HttpApplication — конфигурационные зависимости
|
||||||
|
|
||||||
|
`HttpApplication` требует наличия ключа `cors` в `config/app.php`. Конфиг читается при каждом
|
||||||
|
запросе (в т.ч. OPTIONS-preflight). Если ключ отсутствует — бросается
|
||||||
|
`\RuntimeException('app.cors config is missing')`.
|
||||||
|
|
||||||
|
```php
|
||||||
|
// config/app.php
|
||||||
|
return [
|
||||||
|
'cors' => [
|
||||||
|
'origins' => '*',
|
||||||
|
'methods' => 'GET, POST, PUT, DELETE, OPTIONS',
|
||||||
|
'headers' => 'Content-Type, Authorization',
|
||||||
|
'max_age' => '86400',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
```
|
||||||
34
.claude/decisions/README.md
Normal file
34
.claude/decisions/README.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# Architecture Decision Records (ADR)
|
||||||
|
|
||||||
|
Здесь хранятся записи об архитектурных решениях. Помогают понять **почему** код устроен именно так.
|
||||||
|
|
||||||
|
## Индекс
|
||||||
|
|
||||||
|
| ADR | Название | Статус |
|
||||||
|
|-----|----------|--------|
|
||||||
|
| — | Пока нет ADR | — |
|
||||||
|
|
||||||
|
## Как писать ADR
|
||||||
|
|
||||||
|
Создай новый файл `ADR-NNN-brief-title.md` (NNN = следующий номер) с таким шаблоном:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# ADR-NNN: Краткое название
|
||||||
|
|
||||||
|
## Status
|
||||||
|
Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
Какая проблема стояла. Какие альтернативы рассматривались.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
Что решили.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
Что это даёт. Что ограничивает.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Правила**:
|
||||||
|
- ADR — только **новые файлы**. Существующие ADR не правятся (только Status меняется на "Superseded by ADR-XXX").
|
||||||
|
- Добавляй ADR прямо из feature-ветки — это не вызывает конфликтов.
|
||||||
|
- После мержа — обновить этот индекс (строка в таблице).
|
||||||
56
.claude/development/commands.md
Normal file
56
.claude/development/commands.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Commands Reference
|
||||||
|
|
||||||
|
## Запуск worker
|
||||||
|
|
||||||
|
FrankenPHP стартует PHP-воркеры через Caddyfile:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
frankenphp run --config Caddyfile
|
||||||
|
```
|
||||||
|
|
||||||
|
Воркер-скрипт приложения подключается к фреймворку через `WorkerRunner`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// worker.php
|
||||||
|
$runner = new WorkerRunner($kernel);
|
||||||
|
$runner->run();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Console-команды
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php bin/console <command> [options]
|
||||||
|
```
|
||||||
|
|
||||||
|
Команды регистрируются в контейнере как сервисы с тегом (см. `architecture/console.md`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Composer
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer install # Установить зависимости из lock
|
||||||
|
composer update # Обновить зависимости
|
||||||
|
composer dump-autoload # Пересоздать autoloader
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Docker (если используется в приложении)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose up -d # Запустить сервисы
|
||||||
|
docker compose build # Пересобрать образ
|
||||||
|
docker compose logs -f # Логи в реальном времени
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Git shortcuts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Создать task-файл для новой ветки
|
||||||
|
cp .claude/tasks/_template.md .claude/tasks/active/<branch-name>.md
|
||||||
|
```
|
||||||
75
.claude/development/conventions.md
Normal file
75
.claude/development/conventions.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# Conventions
|
||||||
|
|
||||||
|
## Commit Messages
|
||||||
|
|
||||||
|
```
|
||||||
|
[type] Краткое описание в imperative form
|
||||||
|
```
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
- `Add autoload for routes and services`
|
||||||
|
- `Fix missing CORS config exception`
|
||||||
|
- `Refactor WorkerRunner startup sequence`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Branch Naming
|
||||||
|
|
||||||
|
| Тип | Паттерн | Пример |
|
||||||
|
|-----|---------|--------|
|
||||||
|
| Feature | `feature/description` | `feature/jwt-refresh` |
|
||||||
|
| Fix | `fix/description` | `fix/cors-header` |
|
||||||
|
| Refactor | `refactor/description` | `refactor/kernel-bootstrap` |
|
||||||
|
| Knowledge base / tooling | `kebab-case` | `knowledge-base` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PHP Namespaces
|
||||||
|
|
||||||
|
| Компонент | Namespace |
|
||||||
|
|-----------|-----------|
|
||||||
|
| Core | `Pronchev\Pinecore\` |
|
||||||
|
| HTTP | `Pronchev\Pinecore\Http\` |
|
||||||
|
| Auth | `Pronchev\Pinecore\Auth\` |
|
||||||
|
| ORM | `Pronchev\Pinecore\Orm\` |
|
||||||
|
| Log | `Pronchev\Pinecore\Log\` |
|
||||||
|
| Console | `Pronchev\Pinecore\Console\` |
|
||||||
|
| Model | `Pronchev\Pinecore\Model\` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File & Class Naming
|
||||||
|
|
||||||
|
- PSR-4: файл = имя класса, PascalCase (`WorkerRunner.php` содержит `class WorkerRunner`)
|
||||||
|
- Атрибуты ORM: PascalCase (`#[Collection]`, `#[Field]`)
|
||||||
|
- Interfaces: суффикс `Interface` (`MiddlewareInterface`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Работа с задачами (.claude/tasks/)
|
||||||
|
|
||||||
|
При старте новой ветки:
|
||||||
|
```bash
|
||||||
|
cp .claude/tasks/_template.md .claude/tasks/active/<branch-name>.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Правила:
|
||||||
|
1. Во время разработки — редактируй только свой task-файл
|
||||||
|
2. Можно добавить `decisions/ADR-NNN.md` (новый файл — нет конфликтов)
|
||||||
|
3. Не трогай `architecture/` и `development/` — только в main
|
||||||
|
|
||||||
|
При мерже в main:
|
||||||
|
- Читай секцию "Merge Notes" в task-файле
|
||||||
|
- Обновляй стабильные docs если нужно
|
||||||
|
- Перемести: `tasks/active/<branch>.md` → `tasks/completed/<branch>.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Когда писать ADR
|
||||||
|
|
||||||
|
Создай `decisions/ADR-NNN-title.md` когда:
|
||||||
|
- Вводится новый архитектурный паттерн
|
||||||
|
- Принято нетривиальное решение (и кто-то может спросить "почему так?")
|
||||||
|
- Отвергнута очевидная альтернатива
|
||||||
|
|
||||||
|
ADR — только новые файлы, никогда не правь существующие.
|
||||||
111
.claude/development/patterns.md
Normal file
111
.claude/development/patterns.md
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# Code Patterns
|
||||||
|
|
||||||
|
Переиспользуемые паттерны кодовой базы. Используй существующие — не изобретай новые без необходимости.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Kernel — статический контейнер
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Инициализация (один раз при старте воркера)
|
||||||
|
Kernel::init($container);
|
||||||
|
|
||||||
|
// Получение сервиса
|
||||||
|
$service = Kernel::getContainer()->get(MyService::class);
|
||||||
|
```
|
||||||
|
|
||||||
|
Kernel хранит единственный инстанс контейнера на весь процесс воркера.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. ContainerFactory — сборка контейнера
|
||||||
|
|
||||||
|
```php
|
||||||
|
$factory = new ContainerFactory($config, $environment);
|
||||||
|
$container = $factory->build();
|
||||||
|
```
|
||||||
|
|
||||||
|
Autoload: все файлы из `routes/` и `services/` подхватываются автоматически.
|
||||||
|
Не регистрируй маршруты и сервисы вручную в `index.php` — кладёт файлы в соответствующие директории.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Router и RouteDefinition
|
||||||
|
|
||||||
|
```php
|
||||||
|
// routes/api.php
|
||||||
|
return [
|
||||||
|
new RouteDefinition('GET', '/users/{id}', UserController::class, 'show'),
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
Router находит нужный маршрут по методу и пути, извлекает параметры и вызывает контроллер.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Middleware — цепочка обработки запроса
|
||||||
|
|
||||||
|
```php
|
||||||
|
class MyMiddleware implements MiddlewareInterface {
|
||||||
|
public function handle(Request $request, callable $next): Response {
|
||||||
|
// до
|
||||||
|
$response = $next($request);
|
||||||
|
// после
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Middleware регистрируются в контейнере и применяются ко всем запросам в воркере.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. ORM — атрибуты сущностей
|
||||||
|
|
||||||
|
```php
|
||||||
|
#[Collection('users')]
|
||||||
|
class UserEntity {
|
||||||
|
#[Field('_id')]
|
||||||
|
public string $id;
|
||||||
|
|
||||||
|
#[Field('name')]
|
||||||
|
public string $name;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Repository наследует базовый класс и получает методы `find`, `findOne`, `save`, `delete` из коробки.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. JWT Auth
|
||||||
|
|
||||||
|
```php
|
||||||
|
// AuthMiddleware автоматически валидирует Bearer-токен
|
||||||
|
// В контроллере — получить текущего пользователя из request
|
||||||
|
$user = $request->getAttribute('user');
|
||||||
|
```
|
||||||
|
|
||||||
|
`JwtService` отвечает за выпуск и верификацию токенов. Конфиг: секрет и TTL через `Config`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Config — конфигурация
|
||||||
|
|
||||||
|
```php
|
||||||
|
$value = Config::get('key');
|
||||||
|
$value = Config::get('section.key', $default);
|
||||||
|
```
|
||||||
|
|
||||||
|
Конфиг загружается из `environment.php` (или `.env`). Доступен глобально через статический метод.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. WorkerRunner — цикл обработки запросов
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Внутри worker.php
|
||||||
|
$runner = new WorkerRunner($kernel);
|
||||||
|
$runner->run(); // FrankenPHP loop: запрос → роутинг → middleware → контроллер → ответ
|
||||||
|
```
|
||||||
|
|
||||||
|
`WorkerRunner` перехватывает исключения и возвращает корректный HTTP-ответ даже при ошибке.
|
||||||
61
.claude/development/testing.md
Normal file
61
.claude/development/testing.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# Testing & Debugging
|
||||||
|
|
||||||
|
## Запуск воркера локально
|
||||||
|
|
||||||
|
```bash
|
||||||
|
frankenphp run --config Caddyfile
|
||||||
|
```
|
||||||
|
|
||||||
|
Убедись, что переменные окружения заданы (`.env` или `environment.php`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Отладка запросов
|
||||||
|
|
||||||
|
Включи подробное логирование через конфиг:
|
||||||
|
|
||||||
|
```php
|
||||||
|
Config::get('log.level') // DEBUG для максимального вывода
|
||||||
|
```
|
||||||
|
|
||||||
|
Логи пишутся через `LoggerInterface` (Monolog). Смотри `architecture/logging.md` для деталей.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Частые проблемы
|
||||||
|
|
||||||
|
### Воркер не стартует
|
||||||
|
|
||||||
|
- Проверь синтаксис `Caddyfile` и путь до `worker.php`
|
||||||
|
- FrankenPHP требует `FRANKENPHP_CONFIG` или явного указания воркер-скрипта
|
||||||
|
- Проверь, что `Kernel::init()` вызван до первого запроса
|
||||||
|
|
||||||
|
### Маршрут не найден (404)
|
||||||
|
|
||||||
|
- Убедись, что файл с `RouteDefinition` лежит в `routes/` (autoload подхватывает автоматически)
|
||||||
|
- Проверь HTTP-метод и путь: параметры вида `{id}` чувствительны к паттерну
|
||||||
|
|
||||||
|
### JWT не валидируется
|
||||||
|
|
||||||
|
- Проверь, что `Config::get('auth.secret')` не пустой
|
||||||
|
- Убедись, что `AuthMiddleware` зарегистрирован в контейнере
|
||||||
|
- Время жизни токена — `Config::get('auth.ttl')`
|
||||||
|
|
||||||
|
### Ошибка CORS
|
||||||
|
|
||||||
|
- `CorsMiddleware` требует явного конфига (список разрешённых origins)
|
||||||
|
- Если конфиг не задан — бросается `RuntimeException` при старте
|
||||||
|
|
||||||
|
### MongoDB не подключается
|
||||||
|
|
||||||
|
- Проверь DSN в конфиге: `Config::get('mongodb.dsn')`
|
||||||
|
- Проверь, что MongoDB-сервис запущен и доступен из воркера
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Инспекция контейнера
|
||||||
|
|
||||||
|
```php
|
||||||
|
// В dev-режиме: посмотреть все зарегистрированные сервисы
|
||||||
|
$ids = Kernel::getContainer()->getServiceIds();
|
||||||
|
```
|
||||||
42
.claude/tasks/_template.md
Normal file
42
.claude/tasks/_template.md
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# Task: Краткое название
|
||||||
|
|
||||||
|
## Branch
|
||||||
|
`branch-name`
|
||||||
|
|
||||||
|
## Status
|
||||||
|
<!-- In Progress | Blocked | Ready for Review | Merged -->
|
||||||
|
In Progress
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
Что и зачем делается. Один абзац: проблема, решение, ожидаемый результат.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
- [ ] Компонент/файл A
|
||||||
|
- [ ] Компонент/файл B
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
Технические решения, принятые для этой задачи.
|
||||||
|
Ссылки на файлы архитектуры (например: `.claude/architecture/http.md`).
|
||||||
|
|
||||||
|
## Files Changed
|
||||||
|
<!-- Список заполняй по ходу работы -->
|
||||||
|
- `src/...` — что изменено
|
||||||
|
|
||||||
|
## Patterns Used / Introduced
|
||||||
|
<!-- Какие паттерны из .claude/development/patterns.md использованы -->
|
||||||
|
<!-- Какие новые паттерны введены -->
|
||||||
|
- Использован: `WorkerRunner` (см. `.claude/development/patterns.md`)
|
||||||
|
|
||||||
|
## Decisions & Gotchas
|
||||||
|
<!-- Решения, о которых должны знать следующие разработчики -->
|
||||||
|
<!-- Если решение значимое — создай .claude/decisions/ADR-NNN-title.md -->
|
||||||
|
|
||||||
|
## Testing Done
|
||||||
|
<!-- Как проверено -->
|
||||||
|
|
||||||
|
## Merge Notes
|
||||||
|
<!-- Что интегратор должен сделать после мержа в main -->
|
||||||
|
<!-- Большинство задач: ничего не требуется — удали ненужное -->
|
||||||
|
- [ ] Обновить `.claude/architecture/...`
|
||||||
|
- [ ] Обновить `.claude/development/...`
|
||||||
|
- [ ] Добавить `decisions/ADR-NNN.md` для [решения]
|
||||||
0
.claude/tasks/completed/.gitkeep
Normal file
0
.claude/tasks/completed/.gitkeep
Normal file
10
.claude/tasks/completed/knowledge-base.md
Normal file
10
.claude/tasks/completed/knowledge-base.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Task: привести базу знаний к структуре из другого проекта.
|
||||||
|
|
||||||
|
## Branch
|
||||||
|
`knowledge-base`
|
||||||
|
|
||||||
|
## Status
|
||||||
|
In Progress
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
В репозитории /home/pronchev/source/bitbucket.pltrm.net/trends выработана система накопления базы знаний о проекте и механизм развития проекта с параллельным поддержание базы знаний в актуальном состоянии. Нужно перенести принципы работы и структуру базы знаний в текущий проект.
|
||||||
18
CLAUDE.md
18
CLAUDE.md
@@ -12,16 +12,16 @@ No lint or test commands configured yet.
|
|||||||
|
|
||||||
## Knowledge base
|
## Knowledge base
|
||||||
|
|
||||||
Detailed implementation docs: [.claude/INDEX.md](.claude/INDEX.md)
|
Full index: [.claude/README.md](.claude/README.md)
|
||||||
|
|
||||||
- [Architecture & request lifecycle](.claude/kb/architecture.md)
|
- [Architecture & request lifecycle](.claude/architecture/overview.md)
|
||||||
- [Bootstrap: Kernel, Config, Environment, ContainerFactory](.claude/kb/bootstrap.md)
|
- [Bootstrap: Kernel, Config, Environment, ContainerFactory](.claude/architecture/bootstrap.md)
|
||||||
- [HTTP layer: Request, Response, Router, Middleware](.claude/kb/http.md)
|
- [HTTP layer: Request, Response, Router, Middleware](.claude/architecture/http.md)
|
||||||
- [Worker entrypoint & WorkerRunner](.claude/kb/worker.md)
|
- [Worker entrypoint & WorkerRunner](.claude/architecture/worker.md)
|
||||||
- [Auth: JWT, AuthMiddleware](.claude/kb/auth.md)
|
- [Auth: JWT, AuthMiddleware](.claude/architecture/auth.md)
|
||||||
- [Logging](.claude/kb/logging.md)
|
- [Logging](.claude/architecture/logging.md)
|
||||||
- [ORM: MongoDB, entities, repositories](.claude/kb/orm.md)
|
- [ORM: MongoDB, entities, repositories](.claude/architecture/orm.md)
|
||||||
- [Console](.claude/kb/console.md)
|
- [Console](.claude/architecture/console.md)
|
||||||
|
|
||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace Pronchev\Pinecore;
|
|||||||
|
|
||||||
use DI\Container;
|
use DI\Container;
|
||||||
use DI\ContainerBuilder;
|
use DI\ContainerBuilder;
|
||||||
|
use Pronchev\Pinecore\Http\Router;
|
||||||
|
|
||||||
class ContainerFactory
|
class ContainerFactory
|
||||||
{
|
{
|
||||||
@@ -21,6 +22,14 @@ class ContainerFactory
|
|||||||
|
|
||||||
$builder->useAutowiring(true);
|
$builder->useAutowiring(true);
|
||||||
|
|
||||||
|
$routesFile = $basePath . '/config/routes.php';
|
||||||
|
if (file_exists($routesFile)) {
|
||||||
|
$routes = require $routesFile;
|
||||||
|
$builder->addDefinitions([
|
||||||
|
Router::class => fn() => new Router($routes),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$servicesFile = $basePath . '/config/services.php';
|
$servicesFile = $basePath . '/config/services.php';
|
||||||
if (file_exists($servicesFile)) {
|
if (file_exists($servicesFile)) {
|
||||||
$definitions = require $servicesFile;
|
$definitions = require $servicesFile;
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ final class HttpApplication
|
|||||||
/** @return array<string, string> */
|
/** @return array<string, string> */
|
||||||
private function corsHeaders(): array
|
private function corsHeaders(): array
|
||||||
{
|
{
|
||||||
$cors = $this->config->get('app.cors');
|
$cors = $this->corsConfig();
|
||||||
return [
|
return [
|
||||||
'Access-Control-Allow-Origin' => $cors['origins'],
|
'Access-Control-Allow-Origin' => $cors['origins'],
|
||||||
'Access-Control-Allow-Methods' => $cors['methods'],
|
'Access-Control-Allow-Methods' => $cors['methods'],
|
||||||
@@ -88,10 +88,20 @@ final class HttpApplication
|
|||||||
|
|
||||||
private function emitCorsHeaders(): void
|
private function emitCorsHeaders(): void
|
||||||
{
|
{
|
||||||
$cors = $this->config->get('app.cors');
|
$cors = $this->corsConfig();
|
||||||
header('Access-Control-Allow-Origin: ' . $cors['origins']);
|
header('Access-Control-Allow-Origin: ' . $cors['origins']);
|
||||||
header('Access-Control-Allow-Methods: ' . $cors['methods']);
|
header('Access-Control-Allow-Methods: ' . $cors['methods']);
|
||||||
header('Access-Control-Allow-Headers: ' . $cors['headers']);
|
header('Access-Control-Allow-Headers: ' . $cors['headers']);
|
||||||
header('Access-Control-Max-Age: ' . $cors['max_age']);
|
header('Access-Control-Max-Age: ' . $cors['max_age']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return array<string, mixed> */
|
||||||
|
private function corsConfig(): array
|
||||||
|
{
|
||||||
|
$cors = $this->config->get('app.cors');
|
||||||
|
if (!is_array($cors)) {
|
||||||
|
throw new \RuntimeException('app.cors config is missing');
|
||||||
|
}
|
||||||
|
return $cors;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user