Compare commits

...

2 Commits

Author SHA1 Message Date
DanielS
d5593900fb feat(cron): add automated sync endpoint and vercel cron configuration for partners
All checks were successful
Staging Build / build (push) Successful in 2m57s
2026-07-15 00:30:13 +02:00
DanielS
92eb7454dc docs: update database schema documentation in second brain and grand functions 2026-07-15 00:27:03 +02:00
6 changed files with 83 additions and 2 deletions

View File

@@ -83,3 +83,15 @@ Das Datenbankschema besteht aus folgenden Tabellen im Schema `public`:
- `pdf_url` (TEXT)
- `status` (TEXT: `'pending'`, `'active'`, `'completed'`, `'cancelled'`)
- `created_at` (TIMESTAMPTZ)
### `settings` (Systemeinstellungen)
- Globale Shopeinstellungen (SMTP und LicServer).
- `id` (TEXT, Primary Key, z.B. `'licserver'`, `'smtp'`)
- `host` (TEXT)
- `port` (INTEGER)
- `secure` (BOOLEAN)
- `user` (TEXT)
- `pass` (TEXT)
- `licserver_base_url` (TEXT)
- `licserver_api_key` (TEXT)
- `updated_at` (TIMESTAMPTZ)

View File

@@ -46,3 +46,19 @@
- `order_data` (JSONB)
- `pdf_url` (TEXT)
- `status` (TEXT)
## `categories` (Kategorien)
- Steuert das Layout und Verhalten im Wizard.
- `id` (UUID, Primary Key)
- `name` (TEXT)
- `is_required` (BOOLEAN)
- `allow_multiselect` (BOOLEAN)
- `sort_order` (INTEGER)
- `show_in_branches` (BOOLEAN)
## `settings` (Systemeinstellungen)
- Globale Shopeinstellungen (SMTP & Lizenzserver).
- `id` (TEXT, Primary Key, z.B. `'licserver'`, `'smtp'`)
- `host`, `port`, `secure`, `user`, `pass` (SMTP-Konfiguration)
- `licserver_base_url`, `licserver_api_key` (CASPOS Lizenzserver-Einstellungen)
- `updated_at` (TIMESTAMPTZ)

View File

@@ -0,0 +1,25 @@
import { NextRequest, NextResponse } from 'next/server'
import { syncCompaniesFromLicServer } from '@/lib/actions/companies'
export const dynamic = 'force-dynamic'
export async function GET(req: NextRequest) {
// Check authorization header
const authHeader = req.headers.get('authorization')
const cronSecret = process.env.CRON_SECRET
// Secure the cron endpoint in production
if (process.env.NODE_ENV === 'production' && cronSecret) {
if (authHeader !== `Bearer ${cronSecret}`) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
}
try {
const res = await syncCompaniesFromLicServer()
return NextResponse.json({ success: true, count: res.count })
} catch (err: any) {
console.error('[cron] Sync failed:', err)
return NextResponse.json({ error: err.message || 'Sync failed' }, { status: 500 })
}
}

View File

@@ -1,7 +1,7 @@
'use server'
import { createAdminClient } from '@/lib/supabase/admin'
import { revalidatePath, unstable_noStore as noStore } from 'next/cache'
import { getLicServerConfig } from './licserver-config'
import { getLicServerConfig, getLicServerConfigSystem } from './licserver-config'
export async function getCompanies() {
noStore()
@@ -222,7 +222,7 @@ export async function adminDeleteEndCustomer(id: string) {
export async function syncCompaniesFromLicServer() {
const admin = createAdminClient()
const cfg = await getLicServerConfig()
const cfg = await getLicServerConfigSystem()
if (!cfg.base_url || !cfg.api_key) {
throw new Error('LicServer ist nicht konfiguriert.')

View File

@@ -1,6 +1,7 @@
'use server'
import { createClient } from '@/lib/supabase/server'
import { createAdminClient } from '@/lib/supabase/admin'
export interface LicServerConfig {
base_url: string | null
@@ -90,3 +91,22 @@ export async function testLicServerConnection(): Promise<{ ok: boolean; message:
return { ok: false, message: `Nicht erreichbar: ${err.message}` }
}
}
/**
* System version of getLicServerConfig that bypasses client auth check.
* Used internally by automated background jobs / cron routes.
*/
export async function getLicServerConfigSystem(): Promise<LicServerConfig> {
const admin = createAdminClient()
const { data } = await admin
.from('settings')
.select('licserver_base_url, licserver_api_key')
.eq('id', 'licserver')
.single()
return {
base_url: data?.licserver_base_url || process.env.LICSERVER_BASE_URL || null,
api_key: data?.licserver_api_key || process.env.LICSERVER_API_KEY || null,
}
}

8
shop/vercel.json Normal file
View File

@@ -0,0 +1,8 @@
{
"crons": [
{
"path": "/api/cron/sync-companies",
"schedule": "0 */6 * * *"
}
]
}