Перейти к содержанию

Конфигурация и передача NestJS API

API «Диспетчера» теперь имеет модульный граф, DTO, guards, trace, PostgreSQL repository и транзакционное изменение. Последний шаг определяет, как другой человек подготовит среду и поймёт границы результата. Конфигурация должна остановить неполный профиль раньше случайной работы, а README — различить написанные файлы и выполненные проверки. Результат главы — одна конечная версия серверного проекта с собственным SQL и договором подключения Angular, пригодная для самостоятельного воспроизведения.

Архив не требует клиентского курса. В нём есть CONTRACT.md, .env.example, package.json, tsconfig, все src-файлы и schema/seed. Читатель может использовать HTTP из README без браузера Angular. Для общего проекта достаточно согласовать /api paths и публичные tokens; модель Ticket и статусы уже одинаковы. Такая независимость позволяет изучить backend сначала, не создавая промежуточный другой предметный мир или временные id, которые затем пришлось бы менять на rq-101…103.

Проверка профиля запуска

Ниже полный validateConfig из config.ts. ConfigModule.forRoot передаёт ему входное окружение и загруженный .env. Функция проверяет DATABASE_URL, разные demo tokens и порт 1024–65535. Возвращаемый PORT становится числом, которое main читает через ConfigService. Это ранняя проверка формы настройки; она не подключается к PostgreSQL и не доказывает, что пароль, база и schema действительно доступны. Подготовка ресурса остаётся отдельным читательским действием.

export function validateConfig(input: Record<string,unknown>): Record<string,unknown> {
  const database = input['DATABASE_URL'];
  const viewer = input['DEMO_VIEWER_TOKEN']; const dispatcher = input['DEMO_DISPATCHER_TOKEN'];
  if (typeof database !== 'string' || !/^postgres(ql)?:\/\//.test(database)) throw new Error('Нужен DATABASE_URL PostgreSQL');
  if (typeof viewer !== 'string' || viewer.length < 12 || typeof dispatcher !== 'string' || dispatcher.length < 12 || viewer === dispatcher) throw new Error('Нужны разные учебные токены от 12 символов');
  const port = Number(input['PORT'] ?? 3000);
  if (!Number.isInteger(port) || port < 1024 || port > 65535) throw new Error('PORT: целое число 1024–65535');
  return {...input,PORT:port};
}

DATABASE_URL должен иметь PostgreSQL-префикс, но регулярное выражение не является полной проверкой любой допустимой URL-грамматики. Driver и сервер окончательно оценят строку при соединении. Demo tokens различаются и имеют минимум 12 символов, чтобы учебные роли не совпали случайно. Это не доказательство криптографической безопасности. Значения примера публичны и известны клиенту; они нужны для контролируемого 401/403, а не для защиты production-данных от внешнего пользователя.

Ожидается, что отсутствующая DATABASE_URL или одинаковые tokens остановят bootstrap понятным сообщением. Правильная форма конфигурации позволит создать graph, но последующий SELECT всё ещё может отказать при недоступной базе. Не следует выводить все environment variables в logger ради диагностики: строка соединения содержит credentials. Текущий trace пишет только id/метод/path, а фильтр неожиданных ошибок — тип ошибки. Передача должна сохранять эту границу, когда новый разработчик добавит подробные logs или health endpoint.

Версии и ESM

Common/core/platform-express фиксированы 12.0.1, config 12.0.1, swagger 12.0.2. TypeScript 6.0.3, RxJS 7.8.2, reflect-metadata 0.2.2, class-transformer 0.5.1, class-validator 0.15.1 и pg 8.16.3 перечислены в package.json. Node 22.22.3+ внутри 22.x выбран также для Angular 22. SQL ориентирован на PostgreSQL 18. Наличие точных прямых версий не фиксирует всё дерево транзитивных зависимостей без lockfile; установка не выполнялась, поэтому читатель должен проверить разрешение зависимостей и осознанно сохранить lock после подготовки.

Type module и NodeNext означают, что полученный JavaScript работает как ESM. Относительные серверные импорты содержат .js, decorators включены, emitDecoratorMetadata оставляет информацию времени выполнения для Nest. Старый CommonJS-tsconfig из другого курса нельзя подставить без анализа. Внешние dependencies также выбраны по ESM-профилю Nest 12. Compiler не запускался, поэтому совместимость всего дерева и сформированные метаданные не объявлены подтверждёнными. Это конкретные непроверенные части, а не неопределённая фраза «может понадобиться настройка».

Самостоятельное воспроизведение

README предлагает подготовить отдельную dispatcher_lab и роль dispatcher, заполнить .env, применить 001_schema и 002_seed один раз, затем npm install, build и start. Psql не загружает .env: DATABASE_URL нужно передать или экспортировать отдельно. SQL не идемпотентен и не содержит destructive reset. Такие действия не выполнялись автором. Если читатель хочет повторить лабораторию, он должен управлять собственной отдельной базой, а не запускать seed в рабочем окружении ради быстрого сравнения вывода.

Ожидаемые адреса: API на 127.0.0.1:3000/api/tickets, UI документации /docs, JSON /docs-json. Listen ограничен loopback. CORS не включён; Angular dev-server проксирует /api к Nest через свой proxy.conf.json. Production reverse proxy, TLS и hosting не настроены. Поэтому успешное локальное взаимодействие после самостоятельного запуска не означает готовый внешний сервис. Нужно отдельно определить сетевую публикацию, настоящий доступ, секреты и сопровождение, прежде чем менять bind address.

Сценарии результата привязаны к инвариантам: GET возвращает seed, query отбирает буквально, viewer PATCH получает 403, устаревшая version — 409, успешный PATCH увеличивает version и создаёт историю. У обоих concurrent PATCH одной основы не должно быть двух успешных записей. Неожиданный DB failure должен дать 500 без credentials. Эти проверки перечислены как план, а не как отчёт выполненных тестов. Код, HTTP, SQL, приложение и нагрузки в сессии не запускались; обычная сборка статей сайта не подтверждает их исполнение.

Следующая самостоятельная работа

Текущий API хранит один общий список и свободные transitions status. Нет tenants, настоящих аккаунтов, revocation, rate limit, pagination, backup automation и внешних уведомлений. Request trace не заменяет audit policy, а ticket_events не реализует outbox. Потеря ответа после COMMIT остаётся неоднозначной, idempotency keys не добавлены. Эти границы определяют честный следующий шаг: выбрать один результат и изменить контракт/код последовательно, вместо объявленного «production-ready» на основании нескольких decorators.

Например, tenant-доступ потребует проверенного контекста организации и ограничений SELECT/UPDATE, а не только фильтра Angular. Pagination потребует стабильного порядка и URL/DTO/response continuation. Идемпотентный PATCH потребует ключа операции, хранения результата и правила повторов. Доступность Swagger и подробный health-check имеют другие причины изменения. Все эти темы можно развивать от текущей структуры, но каждая должна иметь собственный наблюдаемый эффект и честный план проверки выбранной среды.

Законченная передача включает понятное направление controller → service → repository → Database, атомарный patch на одном client, внешний DTO-contract и согласованный клиентский unknown-parser. Именно эти свойства сохранены в одной конечной версии ZIP. Читатель получает достаточно исходников для самостоятельного воспроизведения, а также ясные сведения о том, что ещё не было исполнено или реализовано. Серия завершается на этом договоре: написанный учебный API готов к локальной проверке другим человеком, а будущая публикация и production-расширение являются отдельной работой.

Статус примера — not_run. Зависимости, приложение, SQL, HTTP и тесты не запускались. Описанные ответы и изменения интерфейса ожидаемые; чтение документации не является проверкой выполнением. Полная конечная версия находится в архиве исходников, а её ограничения и действия читателя — в README и CONTRACT.md.

Перейдите к оглавлению серии или общему маршруту интерактивной веб-разработки. Механизм этой главы сверяется с официальным первичным источником; конкретные версии и непроверенные части перечислены в договоре курса.