mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 20:54:11 +00:00
fix: resolve all TypeScript errors in production code
- Add Where type imports and proper type assertions in API routes - Add Locale type definitions for locale validation - Fix email-logs/stats route with proper EmailLog typing - Fix newsletter-service interests type and null checks - Remove invalid contact field from OpenAPI metadata - Fix formSubmissionOverrides type casting in payload.config - Fix vcard route Team type casting All 24 TypeScript errors in src/ are now resolved. Test files have separate type issues that don't affect production. 🤖 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
2faefdac1e
commit
9016d3c06c
9 changed files with 54 additions and 38 deletions
|
|
@ -3,8 +3,11 @@
|
||||||
|
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { getPayload } from 'payload'
|
import { getPayload } from 'payload'
|
||||||
|
import type { Where } from 'payload'
|
||||||
import config from '@payload-config'
|
import config from '@payload-config'
|
||||||
import type { Category, Media, Post } from '@/payload-types'
|
import type { Category, Media, Post } from '@/payload-types'
|
||||||
|
|
||||||
|
type Locale = 'de' | 'en' | 'all'
|
||||||
import {
|
import {
|
||||||
searchLimiter,
|
searchLimiter,
|
||||||
rateLimitHeaders,
|
rateLimitHeaders,
|
||||||
|
|
@ -49,8 +52,8 @@ export async function GET(request: NextRequest, { params }: RouteParams) {
|
||||||
const includeRelated = searchParams.get('includeRelated') !== 'false' // Default true
|
const includeRelated = searchParams.get('includeRelated') !== 'false' // Default true
|
||||||
|
|
||||||
// Validate locale
|
// Validate locale
|
||||||
const validLocales = ['de', 'en']
|
const validLocales: Locale[] = ['de', 'en']
|
||||||
const locale = localeParam && validLocales.includes(localeParam) ? localeParam : 'de'
|
const locale: Locale = localeParam && validLocales.includes(localeParam as Locale) ? (localeParam as Locale) : 'de'
|
||||||
|
|
||||||
// Parse tenant ID - REQUIRED for tenant isolation
|
// Parse tenant ID - REQUIRED for tenant isolation
|
||||||
const tenantId = tenantParam ? parseInt(tenantParam, 10) : undefined
|
const tenantId = tenantParam ? parseInt(tenantParam, 10) : undefined
|
||||||
|
|
@ -68,7 +71,7 @@ export async function GET(request: NextRequest, { params }: RouteParams) {
|
||||||
const payload = await getPayload({ config })
|
const payload = await getPayload({ config })
|
||||||
|
|
||||||
// Build where clause (tenant is now required)
|
// Build where clause (tenant is now required)
|
||||||
const where: Record<string, unknown> = {
|
const where: Where = {
|
||||||
slug: { equals: slug },
|
slug: { equals: slug },
|
||||||
status: { equals: 'published' },
|
status: { equals: 'published' },
|
||||||
tenant: { equals: tenantId },
|
tenant: { equals: tenantId },
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,11 @@
|
||||||
|
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { getPayload } from 'payload'
|
import { getPayload } from 'payload'
|
||||||
|
import type { Where } from 'payload'
|
||||||
import config from '@payload-config'
|
import config from '@payload-config'
|
||||||
import type { Category, Media, Post } from '@/payload-types'
|
import type { Category, Media, Post } from '@/payload-types'
|
||||||
|
|
||||||
|
type Locale = 'de' | 'en' | 'all'
|
||||||
import {
|
import {
|
||||||
searchLimiter,
|
searchLimiter,
|
||||||
rateLimitHeaders,
|
rateLimitHeaders,
|
||||||
|
|
@ -29,7 +32,7 @@ interface NewsQueryParams {
|
||||||
search?: string
|
search?: string
|
||||||
year?: number
|
year?: number
|
||||||
month?: number
|
month?: number
|
||||||
locale: string
|
locale: Locale
|
||||||
page: number
|
page: number
|
||||||
limit: number
|
limit: number
|
||||||
excludeIds?: number[]
|
excludeIds?: number[]
|
||||||
|
|
@ -51,7 +54,7 @@ async function getNews(payload: Awaited<ReturnType<typeof getPayload>>, params:
|
||||||
} = params
|
} = params
|
||||||
|
|
||||||
// Build where clause
|
// Build where clause
|
||||||
const where: Record<string, unknown> = {
|
const where: Where = {
|
||||||
status: { equals: 'published' },
|
status: { equals: 'published' },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +134,7 @@ async function getNews(payload: Awaited<ReturnType<typeof getPayload>>, params:
|
||||||
// Execute query
|
// Execute query
|
||||||
return payload.find({
|
return payload.find({
|
||||||
collection: 'posts',
|
collection: 'posts',
|
||||||
where,
|
where: where as Where,
|
||||||
sort: '-publishedAt',
|
sort: '-publishedAt',
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
|
|
@ -144,16 +147,16 @@ async function getNews(payload: Awaited<ReturnType<typeof getPayload>>, params:
|
||||||
async function getCategories(
|
async function getCategories(
|
||||||
payload: Awaited<ReturnType<typeof getPayload>>,
|
payload: Awaited<ReturnType<typeof getPayload>>,
|
||||||
tenantId?: number,
|
tenantId?: number,
|
||||||
locale: string = 'de'
|
locale: Locale = 'de'
|
||||||
) {
|
) {
|
||||||
const where: Record<string, unknown> = {}
|
const where: Where = {}
|
||||||
if (tenantId) {
|
if (tenantId) {
|
||||||
where.tenant = { equals: tenantId }
|
where.tenant = { equals: tenantId }
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await payload.find({
|
const result = await payload.find({
|
||||||
collection: 'categories',
|
collection: 'categories',
|
||||||
where,
|
where: where as Where,
|
||||||
sort: 'name',
|
sort: 'name',
|
||||||
limit: 100,
|
limit: 100,
|
||||||
locale,
|
locale,
|
||||||
|
|
@ -172,7 +175,7 @@ async function getArchive(
|
||||||
payload: Awaited<ReturnType<typeof getPayload>>,
|
payload: Awaited<ReturnType<typeof getPayload>>,
|
||||||
tenantId: number // Now required
|
tenantId: number // Now required
|
||||||
) {
|
) {
|
||||||
const where: Record<string, unknown> = {
|
const where: Where = {
|
||||||
status: { equals: 'published' },
|
status: { equals: 'published' },
|
||||||
publishedAt: { exists: true },
|
publishedAt: { exists: true },
|
||||||
tenant: { equals: tenantId },
|
tenant: { equals: tenantId },
|
||||||
|
|
@ -187,7 +190,7 @@ async function getArchive(
|
||||||
while (hasMore) {
|
while (hasMore) {
|
||||||
const result = await payload.find({
|
const result = await payload.find({
|
||||||
collection: 'posts',
|
collection: 'posts',
|
||||||
where,
|
where: where as Where,
|
||||||
sort: '-publishedAt',
|
sort: '-publishedAt',
|
||||||
page,
|
page,
|
||||||
limit: pageSize,
|
limit: pageSize,
|
||||||
|
|
@ -270,8 +273,8 @@ export async function GET(request: NextRequest) {
|
||||||
const includeArchive = searchParams.get('includeArchive') === 'true'
|
const includeArchive = searchParams.get('includeArchive') === 'true'
|
||||||
|
|
||||||
// Validate locale
|
// Validate locale
|
||||||
const validLocales = ['de', 'en']
|
const validLocales: Locale[] = ['de', 'en']
|
||||||
const locale = localeParam && validLocales.includes(localeParam) ? localeParam : 'de'
|
const locale: Locale = localeParam && validLocales.includes(localeParam as Locale) ? (localeParam as Locale) : 'de'
|
||||||
|
|
||||||
// Validate and parse types
|
// Validate and parse types
|
||||||
let types: NewsType | NewsType[] | undefined
|
let types: NewsType | NewsType[] | undefined
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ export async function GET(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate vCard 3.0
|
// Generate vCard 3.0
|
||||||
const vcard = generateVCard(member)
|
const vcard = generateVCard(member as TeamMember)
|
||||||
|
|
||||||
// Return as downloadable file
|
// Return as downloadable file
|
||||||
const filename = `${member.slug || member.name?.toLowerCase().replace(/\s+/g, '-')}.vcf`
|
const filename = `${member.slug || member.name?.toLowerCase().replace(/\s+/g, '-')}.vcf`
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { getPayload } from 'payload'
|
import { getPayload } from 'payload'
|
||||||
|
import type { Where } from 'payload'
|
||||||
import config from '@payload-config'
|
import config from '@payload-config'
|
||||||
|
|
||||||
|
type Locale = 'de' | 'en' | 'all'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Team API
|
* Team API
|
||||||
*
|
*
|
||||||
|
|
@ -44,10 +47,11 @@ export async function GET(request: NextRequest) {
|
||||||
const limit = Math.min(parseInt(searchParams.get('limit') || '50'), 100)
|
const limit = Math.min(parseInt(searchParams.get('limit') || '50'), 100)
|
||||||
const page = parseInt(searchParams.get('page') || '1')
|
const page = parseInt(searchParams.get('page') || '1')
|
||||||
const sort = searchParams.get('sort') || 'order'
|
const sort = searchParams.get('sort') || 'order'
|
||||||
const locale = (searchParams.get('locale') as 'de' | 'en') || 'de'
|
const localeParam = searchParams.get('locale')
|
||||||
|
const locale: Locale = (localeParam === 'de' || localeParam === 'en') ? localeParam : 'de'
|
||||||
|
|
||||||
// Build where clause
|
// Build where clause
|
||||||
const where: Record<string, unknown> = {
|
const where: Where = {
|
||||||
tenant: { equals: parseInt(tenantId) },
|
tenant: { equals: parseInt(tenantId) },
|
||||||
isActive: { equals: true },
|
isActive: { equals: true },
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +98,7 @@ export async function GET(request: NextRequest) {
|
||||||
// Query team members
|
// Query team members
|
||||||
const result = await payload.find({
|
const result = await payload.find({
|
||||||
collection: 'team',
|
collection: 'team',
|
||||||
where,
|
where: where as Where,
|
||||||
sort: sortField,
|
sort: sortField,
|
||||||
limit,
|
limit,
|
||||||
page,
|
page,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,11 @@
|
||||||
|
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { getPayload } from 'payload'
|
import { getPayload } from 'payload'
|
||||||
|
import type { Where } from 'payload'
|
||||||
import config from '@payload-config'
|
import config from '@payload-config'
|
||||||
import type { Media } from '@/payload-types'
|
import type { Media } from '@/payload-types'
|
||||||
|
|
||||||
|
type Locale = 'de' | 'en' | 'all'
|
||||||
import {
|
import {
|
||||||
searchLimiter,
|
searchLimiter,
|
||||||
rateLimitHeaders,
|
rateLimitHeaders,
|
||||||
|
|
@ -127,8 +130,8 @@ export async function GET(request: NextRequest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate locale
|
// Validate locale
|
||||||
const validLocales = ['de', 'en']
|
const validLocales: Locale[] = ['de', 'en']
|
||||||
const locale = localeParam && validLocales.includes(localeParam) ? localeParam : 'de'
|
const locale: Locale = localeParam && validLocales.includes(localeParam as Locale) ? (localeParam as Locale) : 'de'
|
||||||
|
|
||||||
// Validate type if provided
|
// Validate type if provided
|
||||||
if (typeParam && !TIMELINE_TYPES.includes(typeParam as TimelineType)) {
|
if (typeParam && !TIMELINE_TYPES.includes(typeParam as TimelineType)) {
|
||||||
|
|
@ -139,7 +142,7 @@ export async function GET(request: NextRequest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build where clause
|
// Build where clause
|
||||||
const where: Record<string, unknown> = {
|
const where: Where = {
|
||||||
status: { equals: 'published' },
|
status: { equals: 'published' },
|
||||||
tenant: { equals: tenantId },
|
tenant: { equals: tenantId },
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +163,7 @@ export async function GET(request: NextRequest) {
|
||||||
// Execute query
|
// Execute query
|
||||||
const result = await payload.find({
|
const result = await payload.find({
|
||||||
collection: 'timelines',
|
collection: 'timelines',
|
||||||
where,
|
where: where as Where,
|
||||||
sort: '-updatedAt',
|
sort: '-updatedAt',
|
||||||
limit: slugParam ? 1 : 100, // Single or list
|
limit: slugParam ? 1 : 100, // Single or list
|
||||||
locale,
|
locale,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,11 @@
|
||||||
|
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import { getPayload } from 'payload'
|
import { getPayload } from 'payload'
|
||||||
|
import type { Where } from 'payload'
|
||||||
import config from '@payload-config'
|
import config from '@payload-config'
|
||||||
import type { Media } from '@/payload-types'
|
import type { Media } from '@/payload-types'
|
||||||
|
|
||||||
|
type Locale = 'de' | 'en' | 'all'
|
||||||
import {
|
import {
|
||||||
searchLimiter,
|
searchLimiter,
|
||||||
rateLimitHeaders,
|
rateLimitHeaders,
|
||||||
|
|
@ -122,8 +125,8 @@ export async function GET(request: NextRequest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate locale
|
// Validate locale
|
||||||
const validLocales = ['de', 'en']
|
const validLocales: Locale[] = ['de', 'en']
|
||||||
const locale = localeParam && validLocales.includes(localeParam) ? localeParam : 'de'
|
const locale: Locale = localeParam && validLocales.includes(localeParam as Locale) ? (localeParam as Locale) : 'de'
|
||||||
|
|
||||||
// Validate type if provided
|
// Validate type if provided
|
||||||
if (typeParam && !WORKFLOW_TYPES.includes(typeParam as WorkflowType)) {
|
if (typeParam && !WORKFLOW_TYPES.includes(typeParam as WorkflowType)) {
|
||||||
|
|
@ -142,7 +145,7 @@ export async function GET(request: NextRequest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build where clause
|
// Build where clause
|
||||||
const where: Record<string, unknown> = {
|
const where: Where = {
|
||||||
status: { equals: 'published' },
|
status: { equals: 'published' },
|
||||||
tenant: { equals: tenantId },
|
tenant: { equals: tenantId },
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +166,7 @@ export async function GET(request: NextRequest) {
|
||||||
// Execute query
|
// Execute query
|
||||||
const result = await payload.find({
|
const result = await payload.find({
|
||||||
collection: 'workflows',
|
collection: 'workflows',
|
||||||
where,
|
where: where as Where,
|
||||||
sort: '-updatedAt',
|
sort: '-updatedAt',
|
||||||
limit: slugParam ? 1 : 100, // Single or list
|
limit: slugParam ? 1 : 100, // Single or list
|
||||||
locale,
|
locale,
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { getPayload } from 'payload'
|
import { getPayload } from 'payload'
|
||||||
|
import type { Where } from 'payload'
|
||||||
import configPromise from '@payload-config'
|
import configPromise from '@payload-config'
|
||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
|
import type { EmailLog } from '@/payload-types'
|
||||||
import { logAccessDenied } from '@/lib/audit/audit-service'
|
import { logAccessDenied } from '@/lib/audit/audit-service'
|
||||||
import { maskSmtpError } from '@/lib/security/data-masking'
|
import { maskSmtpError } from '@/lib/security/data-masking'
|
||||||
|
|
||||||
|
|
@ -89,7 +91,7 @@ export async function GET(req: NextRequest): Promise<NextResponse> {
|
||||||
const periodDate = getPeriodDate(period)
|
const periodDate = getPeriodDate(period)
|
||||||
|
|
||||||
// Basis-Where für alle Queries
|
// Basis-Where für alle Queries
|
||||||
const baseWhere: Record<string, unknown> = {
|
const baseWhere: Where = {
|
||||||
createdAt: { greater_than_equal: periodDate.toISOString() },
|
createdAt: { greater_than_equal: periodDate.toISOString() },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,7 +103,7 @@ export async function GET(req: NextRequest): Promise<NextResponse> {
|
||||||
// Gesamt
|
// Gesamt
|
||||||
payload.count({
|
payload.count({
|
||||||
collection: 'email-logs',
|
collection: 'email-logs',
|
||||||
where: baseWhere,
|
where: baseWhere as Where,
|
||||||
}),
|
}),
|
||||||
// Gesendet
|
// Gesendet
|
||||||
payload.count({
|
payload.count({
|
||||||
|
|
@ -161,7 +163,7 @@ export async function GET(req: NextRequest): Promise<NextResponse> {
|
||||||
successRate,
|
successRate,
|
||||||
},
|
},
|
||||||
bySource: sourceStats,
|
bySource: sourceStats,
|
||||||
recentFailures: recentFailed.docs.map((doc: Record<string, unknown>) => ({
|
recentFailures: recentFailed.docs.map((doc: EmailLog) => ({
|
||||||
id: doc.id,
|
id: doc.id,
|
||||||
to: doc.to,
|
to: doc.to,
|
||||||
subject: doc.subject,
|
subject: doc.subject,
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ export class NewsletterService {
|
||||||
email: string
|
email: string
|
||||||
firstName?: string
|
firstName?: string
|
||||||
lastName?: string
|
lastName?: string
|
||||||
interests?: string[]
|
interests?: ('general' | 'blog' | 'products' | 'offers' | 'events')[]
|
||||||
source?: string
|
source?: string
|
||||||
ipAddress?: string
|
ipAddress?: string
|
||||||
userAgent?: string
|
userAgent?: string
|
||||||
|
|
@ -245,12 +245,14 @@ export class NewsletterService {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Tenant-ID ermitteln
|
// Tenant-ID ermitteln
|
||||||
const tenantId = typeof subscriber.tenant === 'object'
|
const tenantId = typeof subscriber.tenant === 'object' && subscriber.tenant
|
||||||
? subscriber.tenant.id
|
? subscriber.tenant.id
|
||||||
: subscriber.tenant
|
: subscriber.tenant
|
||||||
|
|
||||||
// Willkommens-E-Mail senden
|
// Willkommens-E-Mail senden
|
||||||
|
if (tenantId) {
|
||||||
await this.sendWelcomeEmail(tenantId as number, subscriber)
|
await this.sendWelcomeEmail(tenantId as number, subscriber)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -308,7 +310,7 @@ export class NewsletterService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tenant-ID ermitteln
|
// Tenant-ID ermitteln
|
||||||
const tenantId = typeof subscriber.tenant === 'object'
|
const tenantId = typeof subscriber.tenant === 'object' && subscriber.tenant
|
||||||
? subscriber.tenant.id
|
? subscriber.tenant.id
|
||||||
: subscriber.tenant
|
: subscriber.tenant
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -308,12 +308,12 @@ export default buildConfig({
|
||||||
// Fix für TypeScript Types Generation - das Plugin braucht explizite relationTo Angaben
|
// Fix für TypeScript Types Generation - das Plugin braucht explizite relationTo Angaben
|
||||||
redirectRelationships: ['pages'],
|
redirectRelationships: ['pages'],
|
||||||
formSubmissionOverrides: {
|
formSubmissionOverrides: {
|
||||||
...formSubmissionOverrides,
|
...(formSubmissionOverrides as Record<string, unknown>),
|
||||||
hooks: {
|
hooks: {
|
||||||
beforeChange: [formSubmissionBeforeChange],
|
beforeChange: [formSubmissionBeforeChange],
|
||||||
afterChange: [sendFormNotification],
|
afterChange: [sendFormNotification],
|
||||||
},
|
},
|
||||||
},
|
} as Parameters<typeof formBuilderPlugin>[0]['formSubmissionOverrides'],
|
||||||
}),
|
}),
|
||||||
redirectsPlugin({
|
redirectsPlugin({
|
||||||
collections: ['pages'],
|
collections: ['pages'],
|
||||||
|
|
@ -330,10 +330,6 @@ export default buildConfig({
|
||||||
title: 'Payload CMS API',
|
title: 'Payload CMS API',
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
description: 'Multi-Tenant CMS API für porwoll.de, complexcaresolutions.de, gunshin.de und zweitmein.ng',
|
description: 'Multi-Tenant CMS API für porwoll.de, complexcaresolutions.de, gunshin.de und zweitmein.ng',
|
||||||
contact: {
|
|
||||||
name: 'C2S GmbH',
|
|
||||||
url: 'https://complexcaresolutions.de',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
// Swagger UI unter /api/docs
|
// Swagger UI unter /api/docs
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue