Этап 1a: фундамент

- Next 16.4 и Payload 3.91 в одном приложении, PostgreSQL с UUID,
  TypeScript 6, ESLint 9, Prettier, Vitest
- Payload: администраторы с ролями, multi-tenant по сайтам, локализация
  en/ru/de/fr/es, интерфейс админки ru/en, языки сайта (sites.locales)
- Коллекции sites, domains, currencies, countries, locations, tags,
  tariffs, payment-systems (manual), media и начальные данные (pnpm seed)
- Proxy: хост → домен, язык и валюта, внутренние маршруты по хосту;
  /admin и /api закрыты на доменах брендов
- Токены и темы брендов, оболочки сайта и кабинета, переключатели языка,
  валюты и темы, заглушки страниц
- /svc/health, юнит systemd veilix-dev.service
- Документация: решения D-022…D-024, команды в CLAUDE.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
andreypr207andClaude Opus 5.5 committed 2026-10-21 05:08:05 +02:00
1 parent 3400f58a5a
commit 7e331c2c9d
140 files changed
+15885 -43

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
import { timingSafeEqual } from 'node:crypto'
import { listActiveDomains } from '@/core/domains/server'
export const dynamic = 'force-dynamic'
const isAuthorized = (request: Request) => {
const expected = process.env.INTERNAL_TOKEN
const given = request.headers.get('x-vx-internal-token')
if (!expected || !given) return false
const a = Buffer.from(given)
const b = Buffer.from(expected)
return a.length === b.length && timingSafeEqual(a, b)
}
/** Список активных доменов для proxy: тот не ходит в Payload сам, а берёт его здесь */
export async function GET(request: Request) {
if (!isAuthorized(request)) return new Response('Not Found', { status: 404 })
return Response.json(await listActiveDomains(), { headers: { 'Cache-Control': 'no-store' } })
}