mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 18:34:13 +00:00
chore: code cleanup, TypeScript fixes, and dependency updates
- Remove unused variables and imports across API routes and workers - Fix TypeScript errors in ConsentLogs.ts (PayloadRequest header access) - Fix TypeScript errors in formSubmissionHooks.ts (add ResponseTracking interface) - Update eslint ignores for coverage, test results, and generated files - Set push: false in payload.config.ts (schema changes only via migrations) - Update dependencies to latest versions (Payload 3.68.4, React 19.2.3) - Add framework update check script and documentation - Regenerate payload-types.ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
3b3440cae5
commit
2faefdac1e
22 changed files with 1561 additions and 1199 deletions
|
|
@ -21,6 +21,7 @@
|
|||
| [x] | Staging-Deployment | DevOps |
|
||||
| [x] | Memory-Problem lösen (Swap) | Infrastruktur |
|
||||
| [ ] | PM2 Cluster Mode testen | Infrastruktur |
|
||||
| [ ] | Payload/Next Releases auf Next.js 16 Support beobachten *(siehe `framework-monitoring.md`)* | Tech Debt |
|
||||
|
||||
### Niedrige Priorität
|
||||
| Status | Task | Bereich |
|
||||
|
|
|
|||
33
docs/anleitungen/framework-monitoring.md
Normal file
33
docs/anleitungen/framework-monitoring.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Framework Monitoring – Next.js & Payload
|
||||
|
||||
Dieser Leitfaden beschreibt, wie wir beobachten, wann Payload offiziell Next.js 16 (oder spätere) Versionen unterstützt und wann wir die Upgrades wieder aufnehmen können.
|
||||
|
||||
## 1. Wöchentlicher Versions-Check
|
||||
|
||||
```
|
||||
pnpm check:frameworks
|
||||
```
|
||||
|
||||
Der Befehl führt `pnpm outdated` nur für Payload-Core und alle Payload-Plugins sowie Next.js aus. Damit sehen wir sofort, ob es neue Veröffentlichungen gibt, die wir evaluieren sollten.
|
||||
|
||||
> Falls du den Check auf CI ausführen möchtest, stelle sicher, dass `pnpm` installiert ist und das Repository bereits `pnpm install` ausgeführt hat.
|
||||
|
||||
## 2. Release Notes verfolgen
|
||||
|
||||
- Payload Releases: https://github.com/payloadcms/payload/releases
|
||||
Abonniere die Repo-Releases („Watch → Releases only“), damit du automatisch benachrichtigt wirst, wenn ein neues Release Next.js 16 als kompatibel markiert.
|
||||
- Next.js Blog: https://nextjs.org/blog
|
||||
Relevant, um Breaking Changes zu erkennen, die Payload evtl. erst später unterstützt.
|
||||
|
||||
## 3. Vorgehen bei neuem Payload-Release
|
||||
|
||||
1. `pnpm check:frameworks` ausführen und prüfen, ob `@payloadcms/next` oder `@payloadcms/ui` eine neue Version anbieten, deren Peer-Dependencies `next@16` erlauben.
|
||||
2. Falls ja:
|
||||
- Branch erstellen (`feature/upgrade-next16`)
|
||||
- `package.json` anpassen (Next.js + Payload) und `pnpm install`
|
||||
- `pnpm lint`, `pnpm typecheck`, `pnpm test` und ein Test-Build (`pnpm build && pnpm test:e2e` falls vorhanden) ausführen.
|
||||
3. Läuft alles fehlerfrei, kann das Update über PR/Merge in `develop`.
|
||||
|
||||
## 4. Erinnerung
|
||||
|
||||
In der To-Do-Liste (`docs/anleitungen/TODO.md`) gibt es einen Eintrag „Payload/Next Releases auf Next.js 16 Support beobachten“. Wenn das Upgrade abgeschlossen ist, kann dieser Task auf erledigt gesetzt werden.
|
||||
|
|
@ -41,6 +41,11 @@ const eslintConfig = [
|
|||
{
|
||||
ignores: [
|
||||
'.next/',
|
||||
'coverage/',
|
||||
'node_modules/',
|
||||
'playwright-report/',
|
||||
'test-results/',
|
||||
'next-env.d.ts',
|
||||
'src/migrations/', // Payload migrations have required but unused params
|
||||
'src/migrations_backup/',
|
||||
],
|
||||
|
|
|
|||
61
package.json
61
package.json
|
|
@ -10,7 +10,8 @@
|
|||
"devsafe": "rm -rf .next && cross-env NODE_OPTIONS=--no-deprecation next dev",
|
||||
"generate:importmap": "cross-env NODE_OPTIONS=--no-deprecation payload generate:importmap",
|
||||
"generate:types": "cross-env NODE_OPTIONS=--no-deprecation payload generate:types",
|
||||
"lint": "cross-env NODE_OPTIONS=--no-deprecation next lint",
|
||||
"lint": "cross-env NODE_OPTIONS=--no-deprecation eslint src",
|
||||
"check:frameworks": "bash ./scripts/check-framework-updates.sh",
|
||||
"typecheck": "cross-env NODE_OPTIONS=--no-deprecation tsc --noEmit",
|
||||
"format:check": "prettier --check \"src/**/*.{ts,tsx,js,jsx}\" --ignore-unknown",
|
||||
"format": "prettier --write \"src/**/*.{ts,tsx,js,jsx}\" --ignore-unknown",
|
||||
|
|
@ -26,50 +27,50 @@
|
|||
"prepare": "test -d .git && (ln -sf ../../scripts/detect-secrets.sh .git/hooks/pre-commit 2>/dev/null || true) || true"
|
||||
},
|
||||
"dependencies": {
|
||||
"@payloadcms/db-postgres": "3.65.0",
|
||||
"@payloadcms/next": "3.65.0",
|
||||
"@payloadcms/plugin-form-builder": "3.65.0",
|
||||
"@payloadcms/plugin-multi-tenant": "^3.65.0",
|
||||
"@payloadcms/plugin-nested-docs": "3.65.0",
|
||||
"@payloadcms/plugin-redirects": "3.65.0",
|
||||
"@payloadcms/plugin-seo": "3.65.0",
|
||||
"@payloadcms/richtext-lexical": "3.65.0",
|
||||
"@payloadcms/translations": "^3.65.0",
|
||||
"@payloadcms/ui": "3.65.0",
|
||||
"@payloadcms/db-postgres": "3.68.4",
|
||||
"@payloadcms/next": "3.68.4",
|
||||
"@payloadcms/plugin-form-builder": "3.68.4",
|
||||
"@payloadcms/plugin-multi-tenant": "3.68.4",
|
||||
"@payloadcms/plugin-nested-docs": "3.68.4",
|
||||
"@payloadcms/plugin-redirects": "3.68.4",
|
||||
"@payloadcms/plugin-seo": "3.68.4",
|
||||
"@payloadcms/richtext-lexical": "3.68.4",
|
||||
"@payloadcms/translations": "3.68.4",
|
||||
"@payloadcms/ui": "3.68.4",
|
||||
"bullmq": "^5.65.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "16.4.7",
|
||||
"graphql": "^16.8.1",
|
||||
"ioredis": "^5.8.2",
|
||||
"next": "15.4.8",
|
||||
"next": "15.5.9",
|
||||
"node-cron": "^4.2.1",
|
||||
"nodemailer": "^7.0.11",
|
||||
"payload": "3.65.0",
|
||||
"payload": "3.68.4",
|
||||
"payload-oapi": "^0.2.5",
|
||||
"react": "19.2.1",
|
||||
"react-dom": "19.2.1",
|
||||
"sharp": "0.34.2"
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3",
|
||||
"sharp": "0.34.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@playwright/test": "1.56.1",
|
||||
"@eslint/eslintrc": "^3.3.3",
|
||||
"@playwright/test": "1.57.0",
|
||||
"@testing-library/react": "16.3.0",
|
||||
"@types/node": "^22.5.4",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/node-cron": "^3.0.11",
|
||||
"@types/nodemailer": "^7.0.4",
|
||||
"@types/react": "19.1.8",
|
||||
"@types/react-dom": "19.1.6",
|
||||
"@types/react": "19.2.7",
|
||||
"@types/react-dom": "19.2.3",
|
||||
"@vitejs/plugin-react": "4.5.2",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"eslint": "^9.16.0",
|
||||
"eslint-config-next": "15.4.7",
|
||||
"@vitest/coverage-v8": "4.0.15",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-next": "15.5.9",
|
||||
"jsdom": "26.1.0",
|
||||
"playwright": "1.56.1",
|
||||
"playwright-core": "1.56.1",
|
||||
"prettier": "^3.2.5",
|
||||
"typescript": "5.7.3",
|
||||
"vite-tsconfig-paths": "5.1.4",
|
||||
"vitest": "3.2.4"
|
||||
"playwright": "1.57.0",
|
||||
"playwright-core": "1.57.0",
|
||||
"prettier": "^3.7.4",
|
||||
"typescript": "5.9.3",
|
||||
"vite-tsconfig-paths": "6.0.0",
|
||||
"vitest": "4.0.15"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.20.2 || >=20.9.0",
|
||||
|
|
|
|||
1647
pnpm-lock.yaml
1647
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
25
scripts/check-framework-updates.sh
Executable file
25
scripts/check-framework-updates.sh
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if ! command -v pnpm >/dev/null 2>&1; then
|
||||
echo "pnpm is required to run this check." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔍 Checking Payload + Next.js versions (peer compatibility)…"
|
||||
pnpm outdated next \
|
||||
payload \
|
||||
@payloadcms/next \
|
||||
@payloadcms/db-postgres \
|
||||
@payloadcms/plugin-form-builder \
|
||||
@payloadcms/plugin-multi-tenant \
|
||||
@payloadcms/plugin-nested-docs \
|
||||
@payloadcms/plugin-redirects \
|
||||
@payloadcms/plugin-seo \
|
||||
@payloadcms/richtext-lexical \
|
||||
@payloadcms/ui
|
||||
|
||||
echo
|
||||
echo "ℹ️ Review Payload release notes: https://github.com/payloadcms/payload/releases"
|
||||
echo "ℹ️ Review Next.js release notes: https://nextjs.org/blog"
|
||||
|
|
@ -19,19 +19,6 @@ const TIMELINE_RATE_LIMIT = 30
|
|||
const TIMELINE_TYPES = ['history', 'milestones', 'releases', 'career', 'events', 'process'] as const
|
||||
type TimelineType = (typeof TIMELINE_TYPES)[number]
|
||||
|
||||
// Event category for filtering
|
||||
const EVENT_CATEGORIES = [
|
||||
'milestone',
|
||||
'founding',
|
||||
'product',
|
||||
'team',
|
||||
'award',
|
||||
'partnership',
|
||||
'expansion',
|
||||
'technology',
|
||||
'other',
|
||||
] as const
|
||||
|
||||
interface TimelineEvent {
|
||||
dateType: string
|
||||
year?: number
|
||||
|
|
|
|||
|
|
@ -28,9 +28,6 @@ const WORKFLOW_TYPES = [
|
|||
] as const
|
||||
type WorkflowType = (typeof WORKFLOW_TYPES)[number]
|
||||
|
||||
// Step types for filtering
|
||||
const STEP_TYPES = ['task', 'decision', 'milestone', 'approval', 'wait', 'automatic'] as const
|
||||
|
||||
// Valid complexity values (must match Workflows.ts select options)
|
||||
const COMPLEXITY_VALUES = ['simple', 'medium', 'complex', 'very_complex'] as const
|
||||
type ComplexityValue = (typeof COMPLEXITY_VALUES)[number]
|
||||
|
|
|
|||
|
|
@ -169,10 +169,10 @@ export async function GET(req: NextRequest): Promise<NextResponse> {
|
|||
}
|
||||
}
|
||||
|
||||
// Logs abrufen - Type assertion für where da email-logs noch nicht in payload-types
|
||||
const result = await (payload.find as Function)({
|
||||
type FindArgs = Parameters<typeof payload.find>[0]
|
||||
const result = await payload.find({
|
||||
collection: 'email-logs',
|
||||
where,
|
||||
where: where as FindArgs['where'],
|
||||
limit,
|
||||
sort: '-createdAt',
|
||||
depth: 1,
|
||||
|
|
|
|||
|
|
@ -97,33 +97,29 @@ export async function GET(req: NextRequest): Promise<NextResponse> {
|
|||
baseWhere.tenant = { in: tenantFilter }
|
||||
}
|
||||
|
||||
// Statistiken parallel abrufen - Type assertions für email-logs Collection
|
||||
const countFn = payload.count as Function
|
||||
const findFn = payload.find as Function
|
||||
|
||||
const [totalResult, sentResult, failedResult, pendingResult, recentFailed] = await Promise.all([
|
||||
// Gesamt
|
||||
countFn({
|
||||
payload.count({
|
||||
collection: 'email-logs',
|
||||
where: baseWhere,
|
||||
}),
|
||||
// Gesendet
|
||||
countFn({
|
||||
payload.count({
|
||||
collection: 'email-logs',
|
||||
where: { ...baseWhere, status: { equals: 'sent' } },
|
||||
}),
|
||||
// Fehlgeschlagen
|
||||
countFn({
|
||||
payload.count({
|
||||
collection: 'email-logs',
|
||||
where: { ...baseWhere, status: { equals: 'failed' } },
|
||||
}),
|
||||
// Ausstehend
|
||||
countFn({
|
||||
payload.count({
|
||||
collection: 'email-logs',
|
||||
where: { ...baseWhere, status: { equals: 'pending' } },
|
||||
}),
|
||||
// Letzte 5 fehlgeschlagene (für Quick-View)
|
||||
findFn({
|
||||
payload.find({
|
||||
collection: 'email-logs',
|
||||
where: { ...baseWhere, status: { equals: 'failed' } },
|
||||
limit: 5,
|
||||
|
|
@ -145,7 +141,7 @@ export async function GET(req: NextRequest): Promise<NextResponse> {
|
|||
|
||||
await Promise.all(
|
||||
sources.map(async (source) => {
|
||||
const result = await countFn({
|
||||
const result = await payload.count({
|
||||
collection: 'email-logs',
|
||||
where: { ...baseWhere, source: { equals: source } },
|
||||
})
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import { getPayload } from 'payload'
|
||||
import config from '@payload-config'
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { enqueuePdf, getPdfJobStatus, getPdfJobResult, isQueueAvailable } from '@/lib/queue'
|
||||
import { enqueuePdf, getPdfJobStatus, isQueueAvailable } from '@/lib/queue'
|
||||
import { generatePdfFromHtml, generatePdfFromUrl } from '@/lib/pdf/pdf-service'
|
||||
import { logAccessDenied } from '@/lib/audit/audit-service'
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,4 @@
|
|||
import configPromise from '@payload-config'
|
||||
import { getPayload } from 'payload'
|
||||
|
||||
export const GET = async (request: Request) => {
|
||||
const payload = await getPayload({
|
||||
config: configPromise,
|
||||
})
|
||||
|
||||
export const GET = async () => {
|
||||
return Response.json({
|
||||
message: 'This is an example of a custom route.',
|
||||
})
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ export const Bookings: CollectionConfig = {
|
|||
timestamps: true,
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
({ data, req, operation }) => {
|
||||
({ data, req }) => {
|
||||
// Auto-set author for new notes
|
||||
if (data?.internalNotes && req.user) {
|
||||
data.internalNotes = data.internalNotes.map((note: Record<string, unknown>) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// src/collections/ConsentLogs.ts
|
||||
|
||||
import type { CollectionConfig } from 'payload'
|
||||
import type { CollectionConfig, PayloadRequest } from 'payload'
|
||||
import crypto from 'crypto'
|
||||
import { env } from '../lib/envValidation'
|
||||
import { authenticatedOnly } from '../lib/tenantAccess'
|
||||
|
|
@ -30,24 +30,21 @@ function anonymizeIp(ip: string, tenantId: string): string {
|
|||
* Extrahiert die Client-IP aus dem Request.
|
||||
* Berücksichtigt Reverse-Proxy-Header.
|
||||
*/
|
||||
function extractClientIp(req: any): string {
|
||||
function extractClientIp(req: PayloadRequest): string {
|
||||
// X-Forwarded-For kann mehrere IPs enthalten (Client, Proxies)
|
||||
const forwarded = req.headers?.['x-forwarded-for']
|
||||
const forwarded = req.headers?.get?.('x-forwarded-for')
|
||||
if (typeof forwarded === 'string') {
|
||||
return forwarded.split(',')[0].trim()
|
||||
}
|
||||
if (Array.isArray(forwarded) && forwarded.length > 0) {
|
||||
return String(forwarded[0]).trim()
|
||||
}
|
||||
|
||||
// X-Real-IP (einzelne IP)
|
||||
const realIp = req.headers?.['x-real-ip']
|
||||
const realIp = req.headers?.get?.('x-real-ip')
|
||||
if (typeof realIp === 'string') {
|
||||
return realIp.trim()
|
||||
}
|
||||
|
||||
// Fallback: Socket Remote Address
|
||||
return req.socket?.remoteAddress || req.ip || 'unknown'
|
||||
// Fallback: unknown (PayloadRequest hat keinen direkten IP-Zugriff mehr)
|
||||
return 'unknown'
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,21 +13,6 @@ import { logEmailFailed } from '../lib/audit/audit-service'
|
|||
const failedEmailCounter: Map<number, { count: number; lastReset: number }> = new Map()
|
||||
const RESET_INTERVAL = 60 * 60 * 1000 // 1 Stunde
|
||||
|
||||
/**
|
||||
* Gibt die Anzahl der fehlgeschlagenen E-Mails für einen Tenant zurück
|
||||
*/
|
||||
function getFailedCount(tenantId: number): number {
|
||||
const now = Date.now()
|
||||
const entry = failedEmailCounter.get(tenantId)
|
||||
|
||||
if (!entry || now - entry.lastReset > RESET_INTERVAL) {
|
||||
failedEmailCounter.set(tenantId, { count: 0, lastReset: now })
|
||||
return 0
|
||||
}
|
||||
|
||||
return entry.count
|
||||
}
|
||||
|
||||
/**
|
||||
* Inkrementiert den Zähler für fehlgeschlagene E-Mails
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
// src/hooks/formSubmissionHooks.ts
|
||||
|
||||
import type {
|
||||
CollectionBeforeChangeHook,
|
||||
CollectionAfterReadHook,
|
||||
FieldHook,
|
||||
} from 'payload'
|
||||
import type { CollectionBeforeChangeHook } from 'payload'
|
||||
|
||||
interface InternalNote {
|
||||
note: string
|
||||
|
|
@ -12,12 +8,21 @@ interface InternalNote {
|
|||
createdAt?: string
|
||||
}
|
||||
|
||||
interface ResponseTracking {
|
||||
responded?: boolean
|
||||
respondedAt?: string
|
||||
respondedBy?: number | string | { id: number | string }
|
||||
method?: string
|
||||
summary?: string
|
||||
}
|
||||
|
||||
interface FormSubmissionDoc {
|
||||
id: number | string
|
||||
status?: string
|
||||
readAt?: string
|
||||
readBy?: number | string | { id: number | string }
|
||||
internalNotes?: InternalNote[]
|
||||
responseTracking?: ResponseTracking
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +103,7 @@ export const setResponseTimestamp: CollectionBeforeChangeHook<FormSubmissionDoc>
|
|||
return {
|
||||
...data,
|
||||
responseTracking: {
|
||||
...data.responseTracking,
|
||||
...(data.responseTracking || {}),
|
||||
respondedAt: new Date().toISOString(),
|
||||
respondedBy: req.user.id,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -154,8 +154,8 @@ export async function createAuditLog(
|
|||
const maskedNewValue = input.newValue ? maskObject(input.newValue) : undefined
|
||||
const maskedMetadata = input.metadata ? maskObject(input.metadata) : undefined
|
||||
|
||||
// Type assertion notwendig bis payload-types.ts regeneriert wird
|
||||
await (payload.create as Function)({
|
||||
type CreateArgs = Parameters<typeof payload.create>[0]
|
||||
await payload.create({
|
||||
collection: 'audit-logs',
|
||||
data: {
|
||||
action: input.action,
|
||||
|
|
@ -174,7 +174,7 @@ export async function createAuditLog(
|
|||
},
|
||||
// Bypass Access Control für System-Logging
|
||||
overrideAccess: true,
|
||||
})
|
||||
} as CreateArgs)
|
||||
} catch (error) {
|
||||
// Fehler beim Audit-Logging sollten die Hauptoperation nicht blockieren
|
||||
// Auch Fehlermeldungen maskieren
|
||||
|
|
@ -473,13 +473,5 @@ function maskSensitiveData(text: string): string {
|
|||
return maskString(text)
|
||||
}
|
||||
|
||||
/**
|
||||
* Maskiert Objekte für Audit-Logs (previousValue, newValue, metadata)
|
||||
*/
|
||||
function maskAuditData(data: Record<string, unknown> | undefined): Record<string, unknown> | undefined {
|
||||
if (!data) return undefined
|
||||
return maskObject(data)
|
||||
}
|
||||
|
||||
// Re-export für externe Nutzung
|
||||
export { maskError, maskObject, maskString }
|
||||
|
|
|
|||
|
|
@ -79,6 +79,6 @@ export const localeNames: Record<Locale, { native: string; english: string }> =
|
|||
* Get locale direction (for RTL support in future)
|
||||
*/
|
||||
export function getLocaleDirection(locale: Locale): 'ltr' | 'rtl' {
|
||||
// Both German and English are LTR
|
||||
return 'ltr'
|
||||
const rtlLocales: Locale[] = []
|
||||
return rtlLocales.includes(locale) ? 'rtl' : 'ltr'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export function startEmailWorker(): Worker<EmailJobData, EmailJobResult> {
|
|||
console.log(`[EmailWorker] Ready (concurrency: ${CONCURRENCY})`)
|
||||
})
|
||||
|
||||
emailWorker.on('completed', (job, result) => {
|
||||
emailWorker.on('completed', (job) => {
|
||||
console.log(`[EmailWorker] Job ${job.id} completed in ${Date.now() - job.timestamp}ms`)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ async function processPdfJob(job: Job<PdfJobData>): Promise<PdfJobResult> {
|
|||
options = {},
|
||||
tenantId,
|
||||
documentType,
|
||||
correlationId,
|
||||
} = job.data
|
||||
|
||||
console.log(`[PdfWorker] Processing job ${job.id} for tenant ${tenantId} (source: ${source})`)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,9 @@ export interface Config {
|
|||
jobs: Job;
|
||||
downloads: Download;
|
||||
events: Event;
|
||||
bookings: Booking;
|
||||
certifications: Certification;
|
||||
projects: Project;
|
||||
'cookie-configurations': CookieConfiguration;
|
||||
'cookie-inventory': CookieInventory;
|
||||
'consent-logs': ConsentLog;
|
||||
|
|
@ -135,6 +138,9 @@ export interface Config {
|
|||
jobs: JobsSelect<false> | JobsSelect<true>;
|
||||
downloads: DownloadsSelect<false> | DownloadsSelect<true>;
|
||||
events: EventsSelect<false> | EventsSelect<true>;
|
||||
bookings: BookingsSelect<false> | BookingsSelect<true>;
|
||||
certifications: CertificationsSelect<false> | CertificationsSelect<true>;
|
||||
projects: ProjectsSelect<false> | ProjectsSelect<true>;
|
||||
'cookie-configurations': CookieConfigurationsSelect<false> | CookieConfigurationsSelect<true>;
|
||||
'cookie-inventory': CookieInventorySelect<false> | CookieInventorySelect<true>;
|
||||
'consent-logs': ConsentLogsSelect<false> | ConsentLogsSelect<true>;
|
||||
|
|
@ -2584,6 +2590,90 @@ export interface Page {
|
|||
blockName?: string | null;
|
||||
blockType: 'comparison';
|
||||
}
|
||||
| {
|
||||
title?: string | null;
|
||||
subtitle?: string | null;
|
||||
description?: string | null;
|
||||
comparisons: {
|
||||
title?: string | null;
|
||||
beforeImage: number | Media;
|
||||
afterImage: number | Media;
|
||||
beforeLabel?: string | null;
|
||||
afterLabel?: string | null;
|
||||
description?: string | null;
|
||||
category?:
|
||||
| (
|
||||
| 'wedding'
|
||||
| 'portrait'
|
||||
| 'retouch'
|
||||
| 'colorgrade'
|
||||
| 'restore'
|
||||
| 'composing'
|
||||
| 'architecture'
|
||||
| 'product'
|
||||
| 'other'
|
||||
)
|
||||
| null;
|
||||
/**
|
||||
* Komma-getrennte Tags für Filterung
|
||||
*/
|
||||
tags?: string | null;
|
||||
metadata?: {
|
||||
client?: string | null;
|
||||
date?: string | null;
|
||||
/**
|
||||
* z.B. Lightroom, Photoshop
|
||||
*/
|
||||
tools?: string | null;
|
||||
duration?: string | null;
|
||||
};
|
||||
showMetadata?: boolean | null;
|
||||
id?: string | null;
|
||||
}[];
|
||||
displayStyle?: ('slider' | 'hover' | 'toggle' | 'side-by-side' | 'fade') | null;
|
||||
sliderOrientation?: ('horizontal' | 'vertical') | null;
|
||||
/**
|
||||
* 0 = links/oben, 100 = rechts/unten
|
||||
*/
|
||||
sliderStartPosition?: number | null;
|
||||
layout?: ('single' | 'grid-2' | 'grid-3' | 'carousel' | 'masonry') | null;
|
||||
aspectRatio?: ('original' | '16-9' | '4-3' | '3-2' | '1-1' | '2-3' | '9-16') | null;
|
||||
sliderHandle?: {
|
||||
style?: ('circle' | 'line' | 'arrows' | 'custom') | null;
|
||||
color?: ('white' | 'black' | 'primary' | 'accent') | null;
|
||||
size?: ('small' | 'medium' | 'large') | null;
|
||||
showLine?: boolean | null;
|
||||
};
|
||||
showLabels?: boolean | null;
|
||||
labelPosition?: ('corners' | 'top' | 'bottom' | 'overlay') | null;
|
||||
labelStyle?: ('badge' | 'text' | 'pill') | null;
|
||||
showFilter?: boolean | null;
|
||||
animation?: {
|
||||
enableAnimation?: boolean | null;
|
||||
autoPlay?: boolean | null;
|
||||
autoPlaySpeed?: number | null;
|
||||
scrollTrigger?: boolean | null;
|
||||
};
|
||||
interactivity?: {
|
||||
enableZoom?: boolean | null;
|
||||
enableFullscreen?: boolean | null;
|
||||
enableSwipe?: boolean | null;
|
||||
enableKeyboard?: boolean | null;
|
||||
};
|
||||
cta?: {
|
||||
showCta?: boolean | null;
|
||||
ctaText?: string | null;
|
||||
ctaLink?: string | null;
|
||||
ctaStyle?: ('primary' | 'secondary' | 'outline' | 'ghost') | null;
|
||||
};
|
||||
backgroundColor?: ('transparent' | 'white' | 'light' | 'dark' | 'black') | null;
|
||||
borderRadius?: ('none' | 'small' | 'medium' | 'large') | null;
|
||||
shadow?: ('none' | 'small' | 'medium' | 'large') | null;
|
||||
spacing?: ('none' | 'small' | 'medium' | 'large') | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'before-after';
|
||||
}
|
||||
)[]
|
||||
| null;
|
||||
seo?: {
|
||||
|
|
@ -4941,6 +5031,429 @@ export interface Workflow {
|
|||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* Terminbuchungen für Fotoshootings
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "bookings".
|
||||
*/
|
||||
export interface Booking {
|
||||
id: number;
|
||||
tenant?: (number | null) | Tenant;
|
||||
customerName: string;
|
||||
customerEmail: string;
|
||||
customerPhone?: string | null;
|
||||
customerCompany?: string | null;
|
||||
serviceType:
|
||||
| 'wedding'
|
||||
| 'portrait'
|
||||
| 'business'
|
||||
| 'event'
|
||||
| 'product'
|
||||
| 'family'
|
||||
| 'newborn'
|
||||
| 'maternity'
|
||||
| 'realestate'
|
||||
| 'other';
|
||||
/**
|
||||
* Optional: Verknüpfung mit einem definierten Service
|
||||
*/
|
||||
service?: (number | null) | Service;
|
||||
date: string;
|
||||
/**
|
||||
* z.B. 14:00 Uhr
|
||||
*/
|
||||
time?: string | null;
|
||||
duration?: ('30' | '60' | '120' | '180' | '240' | '480' | 'custom') | null;
|
||||
locationType?: ('studio' | 'outdoor' | 'customer' | 'event' | 'tbd') | null;
|
||||
locationAddress?: string | null;
|
||||
/**
|
||||
* Wie viele Personen sollen fotografiert werden?
|
||||
*/
|
||||
participants?: number | null;
|
||||
/**
|
||||
* Besondere Wünsche, Ideen oder Anmerkungen
|
||||
*/
|
||||
message?: string | null;
|
||||
/**
|
||||
* Beispielbilder für gewünschten Stil
|
||||
*/
|
||||
referenceImages?:
|
||||
| {
|
||||
image?: (number | null) | Media;
|
||||
note?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
status: 'pending' | 'review' | 'confirmed' | 'deposit' | 'completed' | 'cancelled' | 'noshow';
|
||||
priority?: ('high' | 'normal' | 'low') | null;
|
||||
pricing?: {
|
||||
/**
|
||||
* In Euro
|
||||
*/
|
||||
estimatedPrice?: number | null;
|
||||
finalPrice?: number | null;
|
||||
depositAmount?: number | null;
|
||||
depositPaid?: boolean | null;
|
||||
fullyPaid?: boolean | null;
|
||||
};
|
||||
/**
|
||||
* Nur für interne Verwendung
|
||||
*/
|
||||
internalNotes?:
|
||||
| {
|
||||
note: string;
|
||||
author?: (number | null) | User;
|
||||
createdAt?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
contactHistory?:
|
||||
| {
|
||||
type: 'email_sent' | 'email_received' | 'call' | 'whatsapp' | 'inperson';
|
||||
summary: string;
|
||||
date?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
assignedTo?: (number | null) | User;
|
||||
source?: ('website' | 'phone' | 'email' | 'instagram' | 'facebook' | 'referral' | 'returning' | 'other') | null;
|
||||
/**
|
||||
* Kunde hat Datenschutzerklärung akzeptiert
|
||||
*/
|
||||
gdprConsent?: boolean | null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* Zertifizierungen, Akkreditierungen und Qualitätssiegel
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "certifications".
|
||||
*/
|
||||
export interface Certification {
|
||||
id: number;
|
||||
tenant?: (number | null) | Tenant;
|
||||
name: string;
|
||||
/**
|
||||
* URL-freundlicher Name
|
||||
*/
|
||||
slug: string;
|
||||
description?: {
|
||||
root: {
|
||||
type: string;
|
||||
children: {
|
||||
type: any;
|
||||
version: number;
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
direction: ('ltr' | 'rtl') | null;
|
||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||
indent: number;
|
||||
version: number;
|
||||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
/**
|
||||
* Für Übersichten und Meta-Beschreibungen
|
||||
*/
|
||||
shortDescription?: string | null;
|
||||
type: 'iso' | 'din' | 'accreditation' | 'seal' | 'membership' | 'award' | 'license' | 'approval' | 'other';
|
||||
category?:
|
||||
| (
|
||||
| 'quality'
|
||||
| 'care'
|
||||
| 'medical'
|
||||
| 'hygiene'
|
||||
| 'safety'
|
||||
| 'privacy'
|
||||
| 'environment'
|
||||
| 'hr'
|
||||
| 'it-security'
|
||||
| 'accessibility'
|
||||
| 'other'
|
||||
)
|
||||
| null;
|
||||
issuer: {
|
||||
name: string;
|
||||
logo?: (number | null) | Media;
|
||||
website?: string | null;
|
||||
country?: ('DE' | 'AT' | 'CH' | 'EU' | 'INT') | null;
|
||||
};
|
||||
certNumber?: string | null;
|
||||
issuedDate?: string | null;
|
||||
validUntil?: string | null;
|
||||
renewalCycle?: ('yearly' | '2years' | '3years' | '5years' | 'unlimited') | null;
|
||||
logo?: (number | null) | Media;
|
||||
/**
|
||||
* Das offizielle Zertifikatsdokument
|
||||
*/
|
||||
certificate?: (number | null) | Media;
|
||||
gallery?:
|
||||
| {
|
||||
document?: (number | null) | Media;
|
||||
title?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
scope?: {
|
||||
description?: string | null;
|
||||
/**
|
||||
* Für welche Standorte gilt die Zertifizierung?
|
||||
*/
|
||||
locations?: (number | Location)[] | null;
|
||||
/**
|
||||
* Für welche Leistungen gilt die Zertifizierung?
|
||||
*/
|
||||
services?: (number | Service)[] | null;
|
||||
};
|
||||
requirements?:
|
||||
| {
|
||||
requirement: string;
|
||||
description?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
benefits?:
|
||||
| {
|
||||
title: string;
|
||||
description?: string | null;
|
||||
icon?: ('check' | 'star' | 'shield' | 'heart' | 'lock' | 'search' | 'clock' | 'document') | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
/**
|
||||
* Historie der durchgeführten Audits
|
||||
*/
|
||||
audits?:
|
||||
| {
|
||||
date: string;
|
||||
type?: ('initial' | 'surveillance' | 'recertification' | 'special') | null;
|
||||
result?: ('passed' | 'conditional' | 'failed') | null;
|
||||
notes?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
status: 'active' | 'pending' | 'renewal' | 'suspended' | 'expired' | 'withdrawn';
|
||||
visibility?: ('public' | 'request' | 'internal') | null;
|
||||
/**
|
||||
* Höhere Zahl = höhere Priorität in der Anzeige
|
||||
*/
|
||||
priority?: number | null;
|
||||
showOnHomepage?: boolean | null;
|
||||
seo?: {
|
||||
metaTitle?: string | null;
|
||||
metaDescription?: string | null;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* Projekte, Spiele und kreative Arbeiten
|
||||
*
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "projects".
|
||||
*/
|
||||
export interface Project {
|
||||
id: number;
|
||||
tenant?: (number | null) | Tenant;
|
||||
title: string;
|
||||
slug: string;
|
||||
/**
|
||||
* Kurze, prägnante Beschreibung (1 Zeile)
|
||||
*/
|
||||
tagline?: string | null;
|
||||
description?: {
|
||||
root: {
|
||||
type: string;
|
||||
children: {
|
||||
type: any;
|
||||
version: number;
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
direction: ('ltr' | 'rtl') | null;
|
||||
format: 'left' | 'start' | 'center' | 'right' | 'end' | 'justify' | '';
|
||||
indent: number;
|
||||
version: number;
|
||||
};
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
/**
|
||||
* Für Übersichten und Social Media
|
||||
*/
|
||||
shortDescription?: string | null;
|
||||
type: 'game' | 'demo' | 'mod' | 'tool' | 'assets' | 'prototype' | 'gamejam' | 'tutorial' | 'opensource' | 'other';
|
||||
genres?:
|
||||
| (
|
||||
| 'action'
|
||||
| 'adventure'
|
||||
| 'rpg'
|
||||
| 'strategy'
|
||||
| 'simulation'
|
||||
| 'puzzle'
|
||||
| 'horror'
|
||||
| 'shooter'
|
||||
| 'platformer'
|
||||
| 'racing'
|
||||
| 'sports'
|
||||
| 'fighting'
|
||||
| 'music'
|
||||
| 'visualnovel'
|
||||
| 'survival'
|
||||
| 'sandbox'
|
||||
| 'towerdefense'
|
||||
| 'roguelike'
|
||||
| 'indie'
|
||||
)[]
|
||||
| null;
|
||||
platforms?:
|
||||
| (
|
||||
| 'windows'
|
||||
| 'macos'
|
||||
| 'linux'
|
||||
| 'web'
|
||||
| 'ios'
|
||||
| 'android'
|
||||
| 'playstation'
|
||||
| 'xbox'
|
||||
| 'switch'
|
||||
| 'steamdeck'
|
||||
| 'vr'
|
||||
)[]
|
||||
| null;
|
||||
featuredImage: number | Media;
|
||||
logo?: (number | null) | Media;
|
||||
screenshots?:
|
||||
| {
|
||||
image: number | Media;
|
||||
caption?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
videos?:
|
||||
| {
|
||||
type: 'trailer' | 'gameplay' | 'devlog' | 'tutorial' | 'other';
|
||||
title?: string | null;
|
||||
/**
|
||||
* YouTube, Vimeo oder direkter Link
|
||||
*/
|
||||
url: string;
|
||||
thumbnail?: (number | null) | Media;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
techStack?: {
|
||||
engine?:
|
||||
| (
|
||||
| 'unity'
|
||||
| 'unreal'
|
||||
| 'godot'
|
||||
| 'gamemaker'
|
||||
| 'rpgmaker'
|
||||
| 'construct'
|
||||
| 'custom'
|
||||
| 'renpy'
|
||||
| 'phaser'
|
||||
| 'other'
|
||||
)
|
||||
| null;
|
||||
languages?:
|
||||
| ('csharp' | 'cpp' | 'gdscript' | 'javascript' | 'typescript' | 'python' | 'lua' | 'rust' | 'blueprint')[]
|
||||
| null;
|
||||
/**
|
||||
* z.B. Blender, Aseprite, FMOD
|
||||
*/
|
||||
tools?: string | null;
|
||||
};
|
||||
requirements?: {
|
||||
minimum?: {
|
||||
os?: string | null;
|
||||
cpu?: string | null;
|
||||
ram?: string | null;
|
||||
gpu?: string | null;
|
||||
storage?: string | null;
|
||||
};
|
||||
recommended?: {
|
||||
os?: string | null;
|
||||
cpu?: string | null;
|
||||
ram?: string | null;
|
||||
gpu?: string | null;
|
||||
storage?: string | null;
|
||||
};
|
||||
};
|
||||
releaseDate?: string | null;
|
||||
links?: {
|
||||
website?: string | null;
|
||||
steam?: string | null;
|
||||
itchio?: string | null;
|
||||
epicGames?: string | null;
|
||||
gog?: string | null;
|
||||
playStore?: string | null;
|
||||
appStore?: string | null;
|
||||
github?: string | null;
|
||||
discord?: string | null;
|
||||
twitter?: string | null;
|
||||
};
|
||||
downloads?:
|
||||
| {
|
||||
/**
|
||||
* z.B. "Windows Build", "Demo v0.5"
|
||||
*/
|
||||
title: string;
|
||||
platform?: ('windows' | 'macos' | 'linux' | 'universal') | null;
|
||||
version?: string | null;
|
||||
file?: (number | null) | Media;
|
||||
externalUrl?: string | null;
|
||||
size?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
features?:
|
||||
| {
|
||||
title: string;
|
||||
description?: string | null;
|
||||
icon?: (number | null) | Media;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
team?:
|
||||
| {
|
||||
name: string;
|
||||
role?: string | null;
|
||||
link?: string | null;
|
||||
avatar?: (number | null) | Media;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
gameJam?: {
|
||||
jamName?: string | null;
|
||||
theme?: string | null;
|
||||
/**
|
||||
* z.B. "48 Stunden"
|
||||
*/
|
||||
duration?: string | null;
|
||||
ranking?: string | null;
|
||||
jamLink?: string | null;
|
||||
};
|
||||
/**
|
||||
* Verknüpfte Blog-Posts über dieses Projekt
|
||||
*/
|
||||
devlogs?: (number | Post)[] | null;
|
||||
status: 'development' | 'earlyaccess' | 'released' | 'paused' | 'cancelled' | 'completed';
|
||||
visibility?: ('public' | 'draft' | 'unlisted' | 'private') | null;
|
||||
featured?: boolean | null;
|
||||
/**
|
||||
* Höher = weiter oben
|
||||
*/
|
||||
sortOrder?: number | null;
|
||||
seo?: {
|
||||
metaTitle?: string | null;
|
||||
metaDescription?: string | null;
|
||||
ogImage?: (number | null) | Media;
|
||||
};
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* Cookie-Banner Konfiguration pro Tenant
|
||||
*
|
||||
|
|
@ -5469,6 +5982,18 @@ export interface PayloadLockedDocument {
|
|||
relationTo: 'events';
|
||||
value: number | Event;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'bookings';
|
||||
value: number | Booking;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'certifications';
|
||||
value: number | Certification;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'projects';
|
||||
value: number | Project;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'cookie-configurations';
|
||||
value: number | CookieConfiguration;
|
||||
|
|
@ -7442,6 +7967,82 @@ export interface PagesSelect<T extends boolean = true> {
|
|||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
'before-after'?:
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
subtitle?: T;
|
||||
description?: T;
|
||||
comparisons?:
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
beforeImage?: T;
|
||||
afterImage?: T;
|
||||
beforeLabel?: T;
|
||||
afterLabel?: T;
|
||||
description?: T;
|
||||
category?: T;
|
||||
tags?: T;
|
||||
metadata?:
|
||||
| T
|
||||
| {
|
||||
client?: T;
|
||||
date?: T;
|
||||
tools?: T;
|
||||
duration?: T;
|
||||
};
|
||||
showMetadata?: T;
|
||||
id?: T;
|
||||
};
|
||||
displayStyle?: T;
|
||||
sliderOrientation?: T;
|
||||
sliderStartPosition?: T;
|
||||
layout?: T;
|
||||
aspectRatio?: T;
|
||||
sliderHandle?:
|
||||
| T
|
||||
| {
|
||||
style?: T;
|
||||
color?: T;
|
||||
size?: T;
|
||||
showLine?: T;
|
||||
};
|
||||
showLabels?: T;
|
||||
labelPosition?: T;
|
||||
labelStyle?: T;
|
||||
showFilter?: T;
|
||||
animation?:
|
||||
| T
|
||||
| {
|
||||
enableAnimation?: T;
|
||||
autoPlay?: T;
|
||||
autoPlaySpeed?: T;
|
||||
scrollTrigger?: T;
|
||||
};
|
||||
interactivity?:
|
||||
| T
|
||||
| {
|
||||
enableZoom?: T;
|
||||
enableFullscreen?: T;
|
||||
enableSwipe?: T;
|
||||
enableKeyboard?: T;
|
||||
};
|
||||
cta?:
|
||||
| T
|
||||
| {
|
||||
showCta?: T;
|
||||
ctaText?: T;
|
||||
ctaLink?: T;
|
||||
ctaStyle?: T;
|
||||
};
|
||||
backgroundColor?: T;
|
||||
borderRadius?: T;
|
||||
shadow?: T;
|
||||
spacing?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
};
|
||||
seo?:
|
||||
| T
|
||||
|
|
@ -8490,6 +9091,270 @@ export interface EventsSelect<T extends boolean = true> {
|
|||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "bookings_select".
|
||||
*/
|
||||
export interface BookingsSelect<T extends boolean = true> {
|
||||
tenant?: T;
|
||||
customerName?: T;
|
||||
customerEmail?: T;
|
||||
customerPhone?: T;
|
||||
customerCompany?: T;
|
||||
serviceType?: T;
|
||||
service?: T;
|
||||
date?: T;
|
||||
time?: T;
|
||||
duration?: T;
|
||||
locationType?: T;
|
||||
locationAddress?: T;
|
||||
participants?: T;
|
||||
message?: T;
|
||||
referenceImages?:
|
||||
| T
|
||||
| {
|
||||
image?: T;
|
||||
note?: T;
|
||||
id?: T;
|
||||
};
|
||||
status?: T;
|
||||
priority?: T;
|
||||
pricing?:
|
||||
| T
|
||||
| {
|
||||
estimatedPrice?: T;
|
||||
finalPrice?: T;
|
||||
depositAmount?: T;
|
||||
depositPaid?: T;
|
||||
fullyPaid?: T;
|
||||
};
|
||||
internalNotes?:
|
||||
| T
|
||||
| {
|
||||
note?: T;
|
||||
author?: T;
|
||||
createdAt?: T;
|
||||
id?: T;
|
||||
};
|
||||
contactHistory?:
|
||||
| T
|
||||
| {
|
||||
type?: T;
|
||||
summary?: T;
|
||||
date?: T;
|
||||
id?: T;
|
||||
};
|
||||
assignedTo?: T;
|
||||
source?: T;
|
||||
gdprConsent?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "certifications_select".
|
||||
*/
|
||||
export interface CertificationsSelect<T extends boolean = true> {
|
||||
tenant?: T;
|
||||
name?: T;
|
||||
slug?: T;
|
||||
description?: T;
|
||||
shortDescription?: T;
|
||||
type?: T;
|
||||
category?: T;
|
||||
issuer?:
|
||||
| T
|
||||
| {
|
||||
name?: T;
|
||||
logo?: T;
|
||||
website?: T;
|
||||
country?: T;
|
||||
};
|
||||
certNumber?: T;
|
||||
issuedDate?: T;
|
||||
validUntil?: T;
|
||||
renewalCycle?: T;
|
||||
logo?: T;
|
||||
certificate?: T;
|
||||
gallery?:
|
||||
| T
|
||||
| {
|
||||
document?: T;
|
||||
title?: T;
|
||||
id?: T;
|
||||
};
|
||||
scope?:
|
||||
| T
|
||||
| {
|
||||
description?: T;
|
||||
locations?: T;
|
||||
services?: T;
|
||||
};
|
||||
requirements?:
|
||||
| T
|
||||
| {
|
||||
requirement?: T;
|
||||
description?: T;
|
||||
id?: T;
|
||||
};
|
||||
benefits?:
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
description?: T;
|
||||
icon?: T;
|
||||
id?: T;
|
||||
};
|
||||
audits?:
|
||||
| T
|
||||
| {
|
||||
date?: T;
|
||||
type?: T;
|
||||
result?: T;
|
||||
notes?: T;
|
||||
id?: T;
|
||||
};
|
||||
status?: T;
|
||||
visibility?: T;
|
||||
priority?: T;
|
||||
showOnHomepage?: T;
|
||||
seo?:
|
||||
| T
|
||||
| {
|
||||
metaTitle?: T;
|
||||
metaDescription?: T;
|
||||
};
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "projects_select".
|
||||
*/
|
||||
export interface ProjectsSelect<T extends boolean = true> {
|
||||
tenant?: T;
|
||||
title?: T;
|
||||
slug?: T;
|
||||
tagline?: T;
|
||||
description?: T;
|
||||
shortDescription?: T;
|
||||
type?: T;
|
||||
genres?: T;
|
||||
platforms?: T;
|
||||
featuredImage?: T;
|
||||
logo?: T;
|
||||
screenshots?:
|
||||
| T
|
||||
| {
|
||||
image?: T;
|
||||
caption?: T;
|
||||
id?: T;
|
||||
};
|
||||
videos?:
|
||||
| T
|
||||
| {
|
||||
type?: T;
|
||||
title?: T;
|
||||
url?: T;
|
||||
thumbnail?: T;
|
||||
id?: T;
|
||||
};
|
||||
techStack?:
|
||||
| T
|
||||
| {
|
||||
engine?: T;
|
||||
languages?: T;
|
||||
tools?: T;
|
||||
};
|
||||
requirements?:
|
||||
| T
|
||||
| {
|
||||
minimum?:
|
||||
| T
|
||||
| {
|
||||
os?: T;
|
||||
cpu?: T;
|
||||
ram?: T;
|
||||
gpu?: T;
|
||||
storage?: T;
|
||||
};
|
||||
recommended?:
|
||||
| T
|
||||
| {
|
||||
os?: T;
|
||||
cpu?: T;
|
||||
ram?: T;
|
||||
gpu?: T;
|
||||
storage?: T;
|
||||
};
|
||||
};
|
||||
releaseDate?: T;
|
||||
links?:
|
||||
| T
|
||||
| {
|
||||
website?: T;
|
||||
steam?: T;
|
||||
itchio?: T;
|
||||
epicGames?: T;
|
||||
gog?: T;
|
||||
playStore?: T;
|
||||
appStore?: T;
|
||||
github?: T;
|
||||
discord?: T;
|
||||
twitter?: T;
|
||||
};
|
||||
downloads?:
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
platform?: T;
|
||||
version?: T;
|
||||
file?: T;
|
||||
externalUrl?: T;
|
||||
size?: T;
|
||||
id?: T;
|
||||
};
|
||||
features?:
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
description?: T;
|
||||
icon?: T;
|
||||
id?: T;
|
||||
};
|
||||
team?:
|
||||
| T
|
||||
| {
|
||||
name?: T;
|
||||
role?: T;
|
||||
link?: T;
|
||||
avatar?: T;
|
||||
id?: T;
|
||||
};
|
||||
gameJam?:
|
||||
| T
|
||||
| {
|
||||
jamName?: T;
|
||||
theme?: T;
|
||||
duration?: T;
|
||||
ranking?: T;
|
||||
jamLink?: T;
|
||||
};
|
||||
devlogs?: T;
|
||||
status?: T;
|
||||
visibility?: T;
|
||||
featured?: T;
|
||||
sortOrder?: T;
|
||||
seo?:
|
||||
| T
|
||||
| {
|
||||
metaTitle?: T;
|
||||
metaDescription?: T;
|
||||
ogImage?: T;
|
||||
};
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "cookie-configurations_select".
|
||||
|
|
|
|||
|
|
@ -209,8 +209,8 @@ export default buildConfig({
|
|||
pool: {
|
||||
connectionString: env.DATABASE_URI,
|
||||
},
|
||||
// Temporär aktiviert für Events Collection
|
||||
push: true,
|
||||
// push: false - Schema-Änderungen nur via Migrationen
|
||||
push: false,
|
||||
}),
|
||||
// Sharp für Bildoptimierung
|
||||
sharp,
|
||||
|
|
|
|||
Loading…
Reference in a new issue