Этап 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

+40
View File
@@ -0,0 +1,40 @@
import type { CollectionBeforeChangeHook, CollectionSlug, Where } from 'payload'
import { ValidationError } from 'payload'
import { message } from '../i18n'
import { relationId } from '../utils'
/**
* Значение поля уникально в пределах сайта. Гарантию даёт составной индекс в базе,
* а хук нужен для понятного сообщения вместо ошибки базы.
*/
export const uniqueInSite =
(field: string, text: { en: string; ru: string }): CollectionBeforeChangeHook =>
async ({ collection, data, originalDoc, req }) => {
const doc = { ...originalDoc, ...data }
const siteId = relationId(doc.site)
const value = relationId(doc[field]) ?? doc[field]
if (!siteId || value === undefined || value === null) return data
const where: Where = {
and: [
{ site: { equals: siteId } },
{ [field]: { equals: value } },
...(originalDoc?.id ? [{ id: { not_equals: originalDoc.id } }] : []),
],
}
const { totalDocs } = await req.payload.count({
collection: collection.slug as CollectionSlug,
where,
overrideAccess: true,
req,
})
if (totalDocs > 0) {
throw new ValidationError({
collection: collection.slug,
errors: [{ path: field, message: message(req, text) }],
req,
})
}
return data
}