From 29ca8e12278e25c8fd2ef998d9e0de4440cb024d Mon Sep 17 00:00:00 2001 From: Florian Wilde Date: Sat, 18 Jul 2026 00:46:38 +0200 Subject: [PATCH] Migration: Allergene/Zusatzstoffe je Gericht, abschaltbarer Passwort-Login, Favicon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dishes.allergens/additives (text[]): Kennzeichnung wieder pro Gericht statt nur global, referenziert weiterhin die globalen Listen - profiles.password_auth_enabled: Nutzer können die eigene Passwort-Anmeldung deaktivieren; Spalten-Grant + neue Policy "profiles_update_own" (ersetzt profiles_update_own_name) - settings.favicon_path fürs austauschbare Favicon - Lokale PostgreSQL-Kopie (Docker + nativ) auf den neuen Stand gebracht --- lib/types.ts | 10 ++++ supabase/local/10_schema.sql | 15 +++-- supabase/local/20_data.sql | 56 +++++++++---------- .../0004_dish_labels_login_toggle_favicon.sql | 32 +++++++++++ 4 files changed, 79 insertions(+), 34 deletions(-) create mode 100644 supabase/migrations/0004_dish_labels_login_toggle_favicon.sql diff --git a/lib/types.ts b/lib/types.ts index da2943e..16c33f3 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -5,6 +5,7 @@ export interface Profile { email: string; full_name: string; role: Role; + password_auth_enabled: boolean; created_at: string; } @@ -19,6 +20,8 @@ export interface Dish { id: string; name: string; price: number; + allergens: string[]; + additives: string[]; } export interface MenuEntry { @@ -73,3 +76,10 @@ export function logoUrl(path: string | null | undefined): string | null { if (!path) return null; return `${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/branding/${path}`; } + +export function faviconUrl(path: string | null | undefined): string | null { + if (!path) return null; + return `${process.env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/branding/${path}`; +} + +export const SITE_TITLE = process.env.SITE_TITLE?.trim() || "Canteen Menu"; diff --git a/supabase/local/10_schema.sql b/supabase/local/10_schema.sql index 0ec2cac..7432544 100644 --- a/supabase/local/10_schema.sql +++ b/supabase/local/10_schema.sql @@ -2,6 +2,7 @@ -- PostgreSQL database dump -- + -- Dumped from database version 17.6 -- Dumped by pg_dump version 17.10 @@ -21,9 +22,6 @@ SET row_security = off; -- Name: public; Type: SCHEMA; Schema: -; Owner: - -- --- Das "public"-Schema existiert im offiziellen postgres-Image bereits; --- CREATE SCHEMA würde dort mit ON_ERROR_STOP=1 das komplette Init-Skript --- abbrechen. CREATE SCHEMA IF NOT EXISTS public; @@ -132,7 +130,9 @@ CREATE TABLE public.dishes ( name text NOT NULL, price numeric(6,2) DEFAULT 0 NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, - updated_at timestamp with time zone DEFAULT now() NOT NULL + updated_at timestamp with time zone DEFAULT now() NOT NULL, + allergens text[] DEFAULT '{}'::text[] NOT NULL, + additives text[] DEFAULT '{}'::text[] NOT NULL ); @@ -160,6 +160,7 @@ CREATE TABLE public.profiles ( full_name text DEFAULT ''::text NOT NULL, role text DEFAULT 'staff'::text NOT NULL, created_at timestamp with time zone DEFAULT now() NOT NULL, + password_auth_enabled boolean DEFAULT true NOT NULL, CONSTRAINT profiles_role_check CHECK ((role = ANY (ARRAY['admin'::text, 'staff'::text]))) ); @@ -185,6 +186,7 @@ CREATE TABLE public.settings ( colors jsonb DEFAULT '{}'::jsonb NOT NULL, logo_path text, updated_at timestamp with time zone DEFAULT now() NOT NULL, + favicon_path text, CONSTRAINT settings_id_check CHECK ((id = 1)) ); @@ -392,10 +394,10 @@ CREATE POLICY profiles_select_own_or_admin ON public.profiles FOR SELECT TO auth -- --- Name: profiles profiles_update_own_name; Type: POLICY; Schema: public; Owner: - +-- Name: profiles profiles_update_own; Type: POLICY; Schema: public; Owner: - -- -CREATE POLICY profiles_update_own_name ON public.profiles FOR UPDATE TO authenticated USING ((id = ( SELECT auth.uid() AS uid))) WITH CHECK ((id = ( SELECT auth.uid() AS uid))); +CREATE POLICY profiles_update_own ON public.profiles FOR UPDATE TO authenticated USING ((id = ( SELECT auth.uid() AS uid))) WITH CHECK ((id = ( SELECT auth.uid() AS uid))); -- @@ -435,3 +437,4 @@ CREATE POLICY settings_public_read ON public.settings FOR SELECT TO authenticate -- PostgreSQL database dump complete -- + diff --git a/supabase/local/20_data.sql b/supabase/local/20_data.sql index 4b1f20c..974e28f 100644 --- a/supabase/local/20_data.sql +++ b/supabase/local/20_data.sql @@ -2,7 +2,7 @@ -- PostgreSQL database dump -- -\restrict HfcGijNcMcy9jPlPpFachgl8LfchhPK39kzgfhc84Q6jsOJpHN3jqf6T368FXri +\restrict WmQEI7C1lM8AheyDeBFMpJzZHr1ZhZm5NphQHzcUeS7IAzg73qb94aso6w4qDad -- Dumped from database version 17.6 -- Dumped by pg_dump version 17.10 @@ -76,25 +76,24 @@ ALTER TABLE public.allergens ENABLE TRIGGER ALL; ALTER TABLE public.dishes DISABLE TRIGGER ALL; -COPY public.dishes (id, name, price, created_at, updated_at) FROM stdin; -2b136266-a80d-4c76-8520-38001c92a634 1 Stk. Rindskäsewurst mit Brötchen 2.30 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -bf612ae7-8cdd-4149-8b21-f651631ccc02 Hackfleischbaguette 3.20 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -81c58cc6-7298-4d4a-9997-71d17df5aedf Knusperhähnchen Wrap 3.70 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -cc7fb9d9-a9ab-4c4c-a376-a8fae0e801c9 Leberkäse im Brötchen 2.30 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -a987c96f-25a0-4e5e-b8a8-aab683a01feb Chili con Carne mit Brötchen 3.90 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -14ef6893-93a7-4649-afe3-d6b6bdf5903c Schnitzel Baguette 3.50 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -ec3c5e37-9cbc-4c92-ab05-1e3fb942c504 Penne mit Grünen Spargel und Garnelenspieße 5.90 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -dbe5ee6e-8b04-4bf7-99bb-f936f6564217 Bratkartoffel Gemüse Pfanne mit Hähnchenbrust und Dip 5.90 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -c0613fe7-e5c6-489e-afe5-6da2533b2bd4 Schweinefilet im Speckmantel dazu Rahmsoße und Butterspätzle 5.90 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -c5cfa5b4-e502-4b56-b579-b9fbbf817f25 Penne mit Grünen Spargel, get. Tomaten und Cherrytomaten 5.30 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -f8ba1844-1f23-4b23-9e03-f59148f8b2ed Spaghetti mit fruchtiger Tomatensauce und Parmesan 5.30 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -7a6fed05-e0f5-4e97-bdd4-a46c5ef1376a Gebackener Feta mit griechischen Bauernsalat und Baguette 5.30 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -ff40ea65-63bc-4d01-b626-e0c9e5d2acb3 Gemüse-Curry mit Basmatireis 4.90 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -ea26f18b-ddf3-4899-95e7-5dbd0878d90c Kartoffelcremesuppe 1.50 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -6222d5f4-05e3-4af4-a41c-3f8b4c9c5c78 Gulaschsuppe 2.50 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -3c8cf0c2-b0a9-43e3-8233-723d5718a157 Tomatensuppe mit Croutons 1.80 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -2dd85835-5425-4271-9fc0-e5215bbce476 Kürbiscremesuppe 1.80 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 -06df753a-65ed-4bd0-a325-d32c78ec88fa Linseneintopf mit Würstchen 2.20 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 +COPY public.dishes (id, name, price, created_at, updated_at, allergens, additives) FROM stdin; +bf612ae7-8cdd-4149-8b21-f651631ccc02 Hackfleischbaguette 3.20 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +81c58cc6-7298-4d4a-9997-71d17df5aedf Knusperhähnchen Wrap 3.70 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +cc7fb9d9-a9ab-4c4c-a376-a8fae0e801c9 Leberkäse im Brötchen 2.30 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +14ef6893-93a7-4649-afe3-d6b6bdf5903c Schnitzel Baguette 3.50 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +ec3c5e37-9cbc-4c92-ab05-1e3fb942c504 Penne mit Grünen Spargel und Garnelenspieße 5.90 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +dbe5ee6e-8b04-4bf7-99bb-f936f6564217 Bratkartoffel Gemüse Pfanne mit Hähnchenbrust und Dip 5.90 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +c0613fe7-e5c6-489e-afe5-6da2533b2bd4 Schweinefilet im Speckmantel dazu Rahmsoße und Butterspätzle 5.90 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +c5cfa5b4-e502-4b56-b579-b9fbbf817f25 Penne mit Grünen Spargel, get. Tomaten und Cherrytomaten 5.30 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +f8ba1844-1f23-4b23-9e03-f59148f8b2ed Spaghetti mit fruchtiger Tomatensauce und Parmesan 5.30 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +7a6fed05-e0f5-4e97-bdd4-a46c5ef1376a Gebackener Feta mit griechischen Bauernsalat und Baguette 5.30 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +ff40ea65-63bc-4d01-b626-e0c9e5d2acb3 Gemüse-Curry mit Basmatireis 4.90 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +ea26f18b-ddf3-4899-95e7-5dbd0878d90c Kartoffelcremesuppe 1.50 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +6222d5f4-05e3-4af4-a41c-3f8b4c9c5c78 Gulaschsuppe 2.50 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +3c8cf0c2-b0a9-43e3-8233-723d5718a157 Tomatensuppe mit Croutons 1.80 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +2dd85835-5425-4271-9fc0-e5215bbce476 Kürbiscremesuppe 1.80 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +06df753a-65ed-4bd0-a325-d32c78ec88fa Linseneintopf mit Würstchen 2.20 2026-07-17 15:17:02.979184+00 2026-07-17 15:17:02.979184+00 {} {} +a987c96f-25a0-4e5e-b8a8-aab683a01feb Chili con Carne mit Brötchen 3.90 2026-07-17 15:17:02.979184+00 2026-07-17 22:21:35.276672+00 {A} {4} \. @@ -123,7 +122,6 @@ ALTER TABLE public.sections ENABLE TRIGGER ALL; ALTER TABLE public.menu_entries DISABLE TRIGGER ALL; COPY public.menu_entries (id, menu_date, section_key, dish_id, "position", created_at) FROM stdin; -5d1ea849-61b3-48ac-b1e9-48b6b2c7d8c1 2026-07-13 brotzeit 2b136266-a80d-4c76-8520-38001c92a634 0 2026-07-17 15:17:02.979184+00 70469091-417b-47ed-aab5-747ff97e4ad4 2026-07-14 brotzeit bf612ae7-8cdd-4149-8b21-f651631ccc02 0 2026-07-17 15:17:02.979184+00 1e1f9b4e-75e7-413f-a747-c2884675d9f7 2026-07-15 brotzeit 81c58cc6-7298-4d4a-9997-71d17df5aedf 0 2026-07-17 15:17:02.979184+00 7b2089f7-7c01-4d6a-9e68-ebfa594bb713 2026-07-16 brotzeit cc7fb9d9-a9ab-4c4c-a376-a8fae0e801c9 0 2026-07-17 15:17:02.979184+00 @@ -140,7 +138,6 @@ e2bfe62e-12c4-4f68-a7e7-ca1ee30a6039 2026-07-14 suppe 6222d5f4-05e3-4af4-a41c-3f 662902e0-bb5e-4268-b977-cef2ac20dc35 2026-07-15 suppe 3c8cf0c2-b0a9-43e3-8233-723d5718a157 0 2026-07-17 15:17:02.979184+00 6083a3f3-a54e-40c5-be1f-c96e474eb8a0 2026-07-16 suppe 2dd85835-5425-4271-9fc0-e5215bbce476 0 2026-07-17 15:17:02.979184+00 36279cd1-b0e2-46a8-b46c-c23f9f5dbb1b 2026-07-17 suppe 06df753a-65ed-4bd0-a325-d32c78ec88fa 0 2026-07-17 15:17:02.979184+00 -ae3f7ced-23b1-42a9-a5d4-2bfab6c333b7 2026-07-22 brotzeit 2b136266-a80d-4c76-8520-38001c92a634 0 2026-07-17 15:17:02.979184+00 bfa36cb8-82d6-466c-b954-bf82c6a67b95 2026-07-23 brotzeit bf612ae7-8cdd-4149-8b21-f651631ccc02 0 2026-07-17 15:17:02.979184+00 b86caf93-34eb-46a3-bbe4-3a67dcf79be0 2026-07-21 brotzeit 81c58cc6-7298-4d4a-9997-71d17df5aedf 0 2026-07-17 15:17:02.979184+00 d8a962cd-f1cf-4f87-95fb-f5af79cbd0a5 2026-07-20 brotzeit cc7fb9d9-a9ab-4c4c-a376-a8fae0e801c9 0 2026-07-17 15:17:02.979184+00 @@ -158,6 +155,7 @@ a6f66639-7a0a-4129-bcea-c6ac9cbccac3 2026-07-20 suppe 6222d5f4-05e3-4af4-a41c-3f b0dbf487-c704-4ab2-af67-082addc88039 2026-07-23 suppe 3c8cf0c2-b0a9-43e3-8233-723d5718a157 0 2026-07-17 15:17:02.979184+00 d7b5d414-85c2-495a-9945-2ffc10de32ea 2026-07-24 suppe 2dd85835-5425-4271-9fc0-e5215bbce476 0 2026-07-17 15:17:02.979184+00 7a025e66-44b7-43e7-a51b-5564ab8150b1 2026-07-22 suppe 06df753a-65ed-4bd0-a325-d32c78ec88fa 0 2026-07-17 15:17:02.979184+00 +2eb81b52-3c50-4449-bef9-bb12aac9991e 2026-07-13 brotzeit 6222d5f4-05e3-4af4-a41c-3f8b4c9c5c78 0 2026-07-17 15:43:22.829239+00 \. @@ -169,9 +167,11 @@ ALTER TABLE public.menu_entries ENABLE TRIGGER ALL; ALTER TABLE public.profiles DISABLE TRIGGER ALL; -COPY public.profiles (id, email, full_name, role, created_at) FROM stdin; -cee4160a-ab3a-4109-b706-b9f27d515596 fw@wildeflorian.de Florian Wilde admin 2026-07-17 15:17:33.46696+00 -102d405c-b010-41f6-9409-244004a3c567 kantine@example.com Kantinen-Team staff 2026-07-17 15:17:34.233848+00 +COPY public.profiles (id, email, full_name, role, created_at, password_auth_enabled) FROM stdin; +cee4160a-ab3a-4109-b706-b9f27d515596 fw@wildeflorian.de Florian Wilde admin 2026-07-17 15:17:33.46696+00 t +6e3ebbd4-a00a-4b08-a799-1a445a3f9eaa test@test.de Hans admin 2026-07-17 16:56:13.331443+00 t +102d405c-b010-41f6-9409-244004a3c567 kantine@example.com Kantinen-Team staff 2026-07-17 15:17:34.233848+00 t +952b21ad-65a0-4a12-aed1-6c86709e0eb2 kantine@kantine.de Kantine staff 2026-07-17 22:02:36.854844+00 t \. @@ -183,8 +183,8 @@ ALTER TABLE public.profiles ENABLE TRIGGER ALL; ALTER TABLE public.settings DISABLE TRIGGER ALL; -COPY public.settings (id, colors, logo_path, updated_at) FROM stdin; -1 {"rowBg": "#e3e4f1", "accent": "#ff6900", "addBtn": "#6da54c", "primary": "#003388", "rowBgAlt": "#f4f4fa", "deleteBtn": "#e2371d", "headerText": "#ffffff", "primaryDark": "#0d315c"} \N 2026-07-17 15:39:01.866456+00 +COPY public.settings (id, colors, logo_path, updated_at, favicon_path) FROM stdin; +1 {"rowBg": "#e3e4f1", "accent": "#ff6900", "addBtn": "#6da54c", "primary": "#003388", "rowBgAlt": "#f4f4fa", "deleteBtn": "#e2371d", "headerText": "#ffffff", "primaryDark": "#0d315c"} logo-1784305413466.webp 2026-07-17 22:40:52.997491+00 \N \. @@ -194,5 +194,5 @@ ALTER TABLE public.settings ENABLE TRIGGER ALL; -- PostgreSQL database dump complete -- -\unrestrict HfcGijNcMcy9jPlPpFachgl8LfchhPK39kzgfhc84Q6jsOJpHN3jqf6T368FXri +\unrestrict WmQEI7C1lM8AheyDeBFMpJzZHr1ZhZm5NphQHzcUeS7IAzg73qb94aso6w4qDad diff --git a/supabase/migrations/0004_dish_labels_login_toggle_favicon.sql b/supabase/migrations/0004_dish_labels_login_toggle_favicon.sql new file mode 100644 index 0000000..aa35eb8 --- /dev/null +++ b/supabase/migrations/0004_dish_labels_login_toggle_favicon.sql @@ -0,0 +1,32 @@ +-- ============================================================= +-- Allergene/Zusatzstoffe pro Gericht, Passwort-Login abschaltbar, +-- austauschbares Favicon +-- ============================================================= + +-- ---------- Allergene/Zusatzstoffe je Gericht ---------- +-- Referenziert Kürzel aus den globalen Listen (allergens/additives), +-- die weiterhin unterhalb der Speisekarte als Legende dienen. +alter table public.dishes + add column allergens text[] not null default '{}', + add column additives text[] not null default '{}'; + +-- ---------- Passwort-Login pro Benutzer abschaltbar ---------- +alter table public.profiles + add column password_auth_enabled boolean not null default true; + +-- Selbstverwaltung: Nutzer dürfen zusätzlich zum Namen (Migration 0003) +-- jetzt auch dieses eine Flag für ihr eigenes Konto setzen. Weiterhin +-- kein Zugriff auf "role" oder "email" über diesen Weg. +grant update (password_auth_enabled) on public.profiles to authenticated; + +-- Klarerer Name für die inzwischen zwei selbstverwaltbaren Spalten. +drop policy "profiles_update_own_name" on public.profiles; +create policy "profiles_update_own" + on public.profiles for update + to authenticated + using (id = (select auth.uid())) + with check (id = (select auth.uid())); + +-- ---------- Austauschbares Favicon ---------- +alter table public.settings + add column favicon_path text;