Compare commits
2 Commits
2246bdf2be
...
0ec1319753
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ec1319753 | ||
|
|
057012e09f |
@@ -8,3 +8,12 @@
|
||||
- Die ungültige RLS-Policy auf `public.partners` wurde entfernt.
|
||||
- `public.companies` wird stattdessen korrekt durch `Admin manage companies` geschützt.
|
||||
- **Consequences**: Behebt Migrations-Fehler im Staging-Server, CI/CD-Pipeline baut wieder fehlerfrei.
|
||||
|
||||
## ADR-002: Entfernung ungenutzter Lizenztabellen
|
||||
- **Status**: Accepted
|
||||
- **Date**: 2026-07-06
|
||||
- **Context**: Die Tabellen `pos_modules` und `licenses` wurden von einem alten bzw. externen Service genutzt. Im aktuellen Webshop-Frontend werden sie nicht benötigt und führen zu unnötiger RLS- und Integritäts-Komplexität.
|
||||
- **Decision**:
|
||||
- Erstellen einer SQL-Migration zum Löschen (`DROP`) von `licenses` und `pos_modules`.
|
||||
- Anpassung der Integritätsprüfungs-Funktionen `check_database_integrity` und `repair_database_schema` zur Entfernung dieser Relationen.
|
||||
- **Consequences**: Schlankere Datenbankstruktur, RLS-Komplexität verringert und sauberere Codebasis.
|
||||
|
||||
@@ -11,12 +11,12 @@ export function getOrderEmailTemplate(
|
||||
siteUrl: string,
|
||||
isUpdate: boolean = false
|
||||
) {
|
||||
const title = isUpdate ? 'Ihre Anfrage wurde aktualisiert!' : 'Vielen Dank für Ihre Anfrage!'
|
||||
const title = isUpdate ? 'Anfrage geändert' : 'Anfrage erhalten'
|
||||
const intro = isUpdate
|
||||
? `Ihr Anfrage mit der Nummer ${details.orderNumber} wurde erfolgreich aktualisiert.`
|
||||
: 'wir freuen uns sehr über Ihre Anfrage bei CASPOS Shop. Ihre Anfrage wurde erfolgreich entgegengenommen und wird nun verarbeitet.'
|
||||
? `Deine Anfrage ${details.orderNumber} wurde aktualisiert.`
|
||||
: `Deine Anfrage ${details.orderNumber} ist bei uns eingegangen und wird bearbeitet.`
|
||||
|
||||
const text = `Hallo,\n\n${isUpdate ? 'ihre Anfrage wurde erfolgreich aktualisiert!' : 'vielen Dank für Ihre Anfrage bei CASPOS Shop!'}\n\n${isUpdate ? 'Neue Anfragedetails' : 'Anfragedetails'}:\n- Anfrage-Nummer: ${details.orderNumber}\n- Datum: ${details.formattedDate}\n- Endkunde: ${details.customerCompanyName}\n${details.totalDetailsText}\n\nIm Anhang dieser E-Mail finden Sie Ihre ${isUpdate ? 'aktualisierte' : ''} Anfragebestätigung als PDF-Dokument.\n\nPDF herunterladen: ${siteUrl}/api/orders/${details.orderNumber}/download\n\nViele Grüße,\nIhr CASPOS Shop-Team`
|
||||
const text = `Hallo,\n\n${isUpdate ? 'Deine Anfrage wurde aktualisiert.' : 'Deine Anfrage ist bei uns eingegangen.'}\n\nDetails:\n- Nummer: ${details.orderNumber}\n- Datum: ${details.formattedDate}\n- Kunde: ${details.customerCompanyName}\n${details.totalDetailsText}\n\nDeine Anfragebestätigung findest du im Anhang als PDF.\n\nPDF-Link: ${siteUrl}/api/orders/${details.orderNumber}/download\n\nViele Grüße,\nDein CASPOS Team`
|
||||
|
||||
const html = `
|
||||
<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e2e8f0; border-radius: 8px;">
|
||||
@@ -24,10 +24,10 @@ export function getOrderEmailTemplate(
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">Hallo,</p>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">${intro}</p>
|
||||
<div style="background-color: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; padding: 16px; margin: 24px 0;">
|
||||
<h3 style="color: #0f172a; margin-top: 0; margin-bottom: 12px;">${isUpdate ? 'Neue Anfrage-Details' : 'Anfrage-Details'}</h3>
|
||||
<h3 style="color: #0f172a; margin-top: 0; margin-bottom: 12px;">Details</h3>
|
||||
<table style="width: 100%; border-collapse: collapse; font-size: 14px; color: #475569;">
|
||||
<tr>
|
||||
<td style="padding: 4px 0; font-weight: bold; width: 140px;">Anfrage-Nummer:</td>
|
||||
<td style="padding: 4px 0; font-weight: bold; width: 140px;">Nummer:</td>
|
||||
<td style="padding: 4px 0;">${details.orderNumber}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -35,18 +35,17 @@ export function getOrderEmailTemplate(
|
||||
<td style="padding: 4px 0;">${details.formattedDate}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 4px 0; font-weight: bold;">Endkunde:</td>
|
||||
<td style="padding: 4px 0; font-weight: bold;">Kunde:</td>
|
||||
<td style="padding: 4px 0;">${details.customerCompanyName}</td>
|
||||
</tr>
|
||||
${details.totalDetailsHtml}
|
||||
</table>
|
||||
</div>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">Im Anhang dieser E-Mail finden Sie Ihre ${isUpdate ? 'aktualisierte' : ''} Anfragebestätigung als PDF-Dokument.</p>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">Die Bestätigung liegt als PDF im Anhang.</p>
|
||||
<div style="text-align: center; margin: 24px 0;">
|
||||
<a href="${siteUrl}" style="display: inline-block; background-color: #3b82f6; color: #ffffff; text-decoration: none; padding: 12px 24px; border-radius: 6px; font-weight: bold; font-size: 14px;">📄 PDF herunterladen</a>
|
||||
</div>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5; margin-top: 24px;">Mit freundlichen Grüßen,<br>Ihr CASPOS Shop-Team</p>
|
||||
${!isUpdate ? '<hr style="border: 0; border-top: 1px solid #e2e8f0; margin: 24px 0;"><p style="color: #94a3b8; font-size: 12px; text-align: center;">Diese E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.</p>' : ''}
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5; margin-top: 24px;">Viele Grüße,<br>Dein CASPOS Team</p>
|
||||
</div>
|
||||
`
|
||||
|
||||
@@ -54,32 +53,30 @@ export function getOrderEmailTemplate(
|
||||
}
|
||||
|
||||
export function getStatusEmailTemplate(orderNumber: string, oldLabel: string, newLabel: string) {
|
||||
const text = `Hallo,\n\nder Status Ihrer Bestellung mit der Nummer ${orderNumber} hat sich geändert.\n\nNeuer Status: ${newLabel} (vorher: ${oldLabel})\n\nViele Grüße,\nIhr CASPOS Shop-Team`
|
||||
const text = `Hallo,\n\nder Status deiner Anfrage ${orderNumber} hat sich geändert.\n\nStatus: ${newLabel} (vorher: ${oldLabel})\n\nViele Grüße,\nDein CASPOS Team`
|
||||
|
||||
const html = `
|
||||
<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e2e8f0; border-radius: 8px;">
|
||||
<h2 style="color: #0f172a; margin-bottom: 16px;">Status Ihrer Bestellung hat sich geändert</h2>
|
||||
<h2 style="color: #0f172a; margin-bottom: 16px;">Statusänderung</h2>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">Hallo,</p>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">der Status Ihrer Bestellung mit der Nummer <strong>${orderNumber}</strong> wurde aktualisiert.</p>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">der Status deiner Anfrage <strong>${orderNumber}</strong> wurde aktualisiert.</p>
|
||||
<div style="background-color: #f8fafc; border: 1px solid #e2e8f0; border-radius: 6px; padding: 16px; margin: 24px 0;">
|
||||
<table style="width: 100%; border-collapse: collapse; font-size: 14px; color: #475569;">
|
||||
<tr>
|
||||
<td style="padding: 4px 0; font-weight: bold; width: 140px;">Bestellnummer:</td>
|
||||
<td style="padding: 4px 0; font-weight: bold; width: 140px;">Nummer:</td>
|
||||
<td style="padding: 4px 0;">${orderNumber}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 4px 0; font-weight: bold;">Alter Status:</td>
|
||||
<td style="padding: 4px 0; font-weight: bold;">Vorher:</td>
|
||||
<td style="padding: 4px 0; text-decoration: line-through; color: #94a3b8;">${oldLabel}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 4px 0; font-weight: bold;">Neuer Status:</td>
|
||||
<td style="padding: 4px 0; font-weight: bold;">Aktuell:</td>
|
||||
<td style="padding: 4px 0; font-weight: bold; color: #3b82f6;">${newLabel}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">Viele Grüße,<br>Ihr CASPOS Shop-Team</p>
|
||||
<hr style="border: 0; border-top: 1px solid #e2e8f0; margin: 24px 0;">
|
||||
<p style="color: #94a3b8; font-size: 12px; text-align: center;">Diese E-Mail wurde automatisch generiert. Bitte antworten Sie nicht darauf.</p>
|
||||
<p style="color: #475569; font-size: 16px; line-height: 1.5;">Viele Grüße,<br>Dein CASPOS Team</p>
|
||||
</div>
|
||||
`
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
-- Migration: Remove unused pos_modules and licenses tables and reference functions
|
||||
-- 1. Drop the tables (cascade to clean up RLS policies automatically)
|
||||
DROP TABLE IF EXISTS public.licenses CASCADE;
|
||||
DROP TABLE IF EXISTS public.pos_modules CASCADE;
|
||||
|
||||
-- 2. Update database integrity function to remove pos_modules and licenses checks
|
||||
CREATE OR REPLACE FUNCTION public.check_database_integrity()
|
||||
RETURNS jsonb
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
tables_to_check text[] := ARRAY[
|
||||
'users',
|
||||
'settings',
|
||||
'companies',
|
||||
'categories',
|
||||
'products',
|
||||
'product_modules',
|
||||
'orders',
|
||||
'profiles',
|
||||
'end_customers'
|
||||
];
|
||||
t text;
|
||||
t_exists boolean;
|
||||
t_count bigint;
|
||||
tables_result jsonb := jsonb_build_object();
|
||||
result jsonb;
|
||||
BEGIN
|
||||
FOREACH t IN ARRAY tables_to_check LOOP
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = t
|
||||
) INTO t_exists;
|
||||
|
||||
t_count := 0;
|
||||
IF t_exists THEN
|
||||
EXECUTE format('SELECT count(*) FROM public.%I', t) INTO t_count;
|
||||
END IF;
|
||||
|
||||
tables_result := tables_result || jsonb_build_object(t, jsonb_build_object('exists', t_exists, 'count', t_count));
|
||||
END LOOP;
|
||||
|
||||
result := jsonb_build_object(
|
||||
'tables', tables_result,
|
||||
'errors', jsonb_build_object(
|
||||
'foreign_keys', 0
|
||||
)
|
||||
);
|
||||
|
||||
RETURN result;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- 3. Update database repair schema function to remove creation of pos_modules and licenses
|
||||
CREATE OR REPLACE FUNCTION public.repair_database_schema()
|
||||
RETURNS jsonb
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
repaired_tables text[] := '{}';
|
||||
result jsonb;
|
||||
BEGIN
|
||||
-- 1. profiles table
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'profiles') THEN
|
||||
CREATE TABLE public.profiles (
|
||||
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
|
||||
first_name TEXT,
|
||||
last_name TEXT,
|
||||
company_name TEXT,
|
||||
vat_id TEXT,
|
||||
address TEXT,
|
||||
city TEXT,
|
||||
zip_code TEXT,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL
|
||||
);
|
||||
repaired_tables := array_append(repaired_tables, 'profiles');
|
||||
END IF;
|
||||
|
||||
-- 2. end_customers table
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'end_customers') THEN
|
||||
CREATE TABLE public.end_customers (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
partner_id UUID NOT NULL REFERENCES public.companies(id) ON DELETE CASCADE,
|
||||
company_name TEXT NOT NULL,
|
||||
vat_id TEXT,
|
||||
first_name TEXT,
|
||||
last_name TEXT,
|
||||
street TEXT,
|
||||
zip TEXT,
|
||||
city TEXT,
|
||||
is_anonymized BOOLEAN NOT NULL DEFAULT false,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
repaired_tables := array_append(repaired_tables, 'end_customers');
|
||||
END IF;
|
||||
|
||||
-- Enable RLS
|
||||
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE public.end_customers ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Recreate RLS Policies
|
||||
DROP POLICY IF EXISTS "Users can view their own profile" ON public.profiles;
|
||||
CREATE POLICY "Users can view their own profile" ON public.profiles FOR SELECT USING (auth.uid() = id);
|
||||
DROP POLICY IF EXISTS "Users can update their own profile" ON public.profiles;
|
||||
CREATE POLICY "Users can update their own profile" ON public.profiles FOR UPDATE USING (auth.uid() = id);
|
||||
DROP POLICY IF EXISTS "Users can insert their own profile" ON public.profiles;
|
||||
CREATE POLICY "Users can insert their own profile" ON public.profiles FOR INSERT WITH CHECK (auth.uid() = id);
|
||||
|
||||
result := jsonb_build_object(
|
||||
'repaired_tables', repaired_tables
|
||||
);
|
||||
|
||||
RETURN result;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Reload Schema Cache
|
||||
NOTIFY pgrst, 'reload schema';
|
||||
Reference in New Issue
Block a user