feat: implement advanced tagging system, tag weighting, and app focus refactoring
- Implemented reusable TagSelector component with i18n support - Added tag weighting system (popularity scores 1-5) - Created admin panel for tag management - Integrated Nebius AI and Brave Search for 'Magic Scan' - Refactored app focus: removed bottle status, updated counters, and displayed extended bottle details - Updated i18n for German and English - Added database migration scripts
This commit is contained in:
161
tagging_system_migration.sql
Normal file
161
tagging_system_migration.sql
Normal file
@@ -0,0 +1,161 @@
|
||||
-- Migration for Advanced Tagging System
|
||||
|
||||
-- 1. Rename existing 'tasting_tags' to 'tasting_buddies'
|
||||
-- This table currently stores which buddies are part of a tasting.
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT FROM pg_tables WHERE schemaname = 'public' AND tablename = 'tasting_tags') THEN
|
||||
ALTER TABLE tasting_tags RENAME TO tasting_buddies;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 2. Create 'tags' table
|
||||
CREATE TYPE tag_category AS ENUM ('nose', 'taste', 'finish', 'texture');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tags (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name TEXT NOT NULL,
|
||||
category tag_category NOT NULL,
|
||||
is_system_default BOOLEAN DEFAULT false,
|
||||
popularity_score INTEGER DEFAULT 3, -- 1 to 5
|
||||
created_by UUID REFERENCES profiles(id) ON DELETE CASCADE,
|
||||
UNIQUE(name, category)
|
||||
);
|
||||
|
||||
-- 3. Create new 'tasting_tags' junction table (for aroma tags)
|
||||
CREATE TABLE IF NOT EXISTS tasting_tags (
|
||||
tasting_id UUID REFERENCES tastings(id) ON DELETE CASCADE NOT NULL,
|
||||
tag_id UUID REFERENCES tags(id) ON DELETE CASCADE NOT NULL,
|
||||
user_id UUID REFERENCES profiles(id) ON DELETE CASCADE NOT NULL,
|
||||
PRIMARY KEY (tasting_id, tag_id)
|
||||
);
|
||||
|
||||
-- 4. Enable RLS
|
||||
ALTER TABLE tags ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE tasting_tags ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- 5. Policies for 'tags'
|
||||
-- Everyone can read system default tags and their own custom tags
|
||||
DROP POLICY IF EXISTS "tags_select_policy" ON tags;
|
||||
CREATE POLICY "tags_select_policy" ON tags
|
||||
FOR SELECT USING (
|
||||
is_system_default = true OR
|
||||
(SELECT auth.uid()) = created_by OR
|
||||
EXISTS (SELECT 1 FROM admin_users WHERE user_id = (SELECT auth.uid()))
|
||||
);
|
||||
|
||||
-- Users can insert their own custom tags
|
||||
DROP POLICY IF EXISTS "tags_insert_policy" ON tags;
|
||||
CREATE POLICY "tags_insert_policy" ON tags
|
||||
FOR INSERT WITH CHECK (
|
||||
(SELECT auth.uid()) = created_by
|
||||
);
|
||||
|
||||
-- 6. Policies for 'tasting_tags' (junction)
|
||||
DROP POLICY IF EXISTS "tasting_tags_owner_policy" ON tasting_tags;
|
||||
CREATE POLICY "tasting_tags_owner_policy" ON tasting_tags
|
||||
FOR ALL USING ((SELECT auth.uid()) = user_id);
|
||||
|
||||
-- 7. Insert Master List of System Tags
|
||||
INSERT INTO tags (name, category, is_system_default) VALUES
|
||||
-- FRUCHTIG (FRUITY)
|
||||
('Apfel', 'nose', true), ('Apfel', 'taste', true),
|
||||
('Grüner Apfel', 'nose', true), ('Grüner Apfel', 'taste', true),
|
||||
('Bratapfel', 'nose', true), ('Bratapfel', 'taste', true),
|
||||
('Birne', 'nose', true), ('Birne', 'taste', true),
|
||||
('Zitrone', 'nose', true), ('Zitrone', 'taste', true),
|
||||
('Zitrus', 'nose', true), ('Zitrus', 'taste', true),
|
||||
('Orange', 'nose', true), ('Orange', 'taste', true),
|
||||
('Orangenschale', 'nose', true), ('Orangenschale', 'taste', true),
|
||||
('Pfirsich', 'nose', true), ('Pfirsich', 'taste', true),
|
||||
('Aprikose', 'nose', true), ('Aprikose', 'taste', true),
|
||||
('Banane', 'nose', true), ('Banane', 'taste', true),
|
||||
('Ananas', 'nose', true), ('Ananas', 'taste', true),
|
||||
('Tropische Früchte', 'nose', true), ('Tropische Früchte', 'taste', true),
|
||||
('Kirsche', 'nose', true), ('Kirsche', 'taste', true),
|
||||
('Beeren', 'nose', true), ('Beeren', 'taste', true),
|
||||
('Brombeere', 'nose', true), ('Brombeere', 'taste', true),
|
||||
('Himbeere', 'nose', true), ('Himbeere', 'taste', true),
|
||||
('Pflaume', 'nose', true), ('Pflaume', 'taste', true),
|
||||
('Trockenfrüchte', 'nose', true), ('Trockenfrüchte', 'taste', true),
|
||||
('Rosinen', 'nose', true), ('Rosinen', 'taste', true),
|
||||
('Datteln', 'nose', true), ('Datteln', 'taste', true),
|
||||
('Feigen', 'nose', true), ('Feigen', 'taste', true),
|
||||
|
||||
-- SÜSS & CREMIG (SWEET & CREAMY)
|
||||
('Vanille', 'nose', true), ('Vanille', 'taste', true),
|
||||
('Honig', 'nose', true), ('Honig', 'taste', true),
|
||||
('Karamell', 'nose', true), ('Karamell', 'taste', true),
|
||||
('Toffee', 'nose', true), ('Toffee', 'taste', true),
|
||||
('Schokolade', 'nose', true), ('Schokolade', 'taste', true),
|
||||
('Zartbitterschokolade', 'nose', true), ('Zartbitterschokolade', 'taste', true),
|
||||
('Milchschokolade', 'nose', true), ('Milchschokolade', 'taste', true),
|
||||
('Malz', 'nose', true), ('Malz', 'taste', true),
|
||||
('Müsli', 'nose', true), ('Müsli', 'taste', true),
|
||||
('Butter', 'nose', true), ('Butter', 'taste', true),
|
||||
('Butterkeks', 'nose', true), ('Butterkeks', 'taste', true),
|
||||
('Marzipan', 'nose', true), ('Marzipan', 'taste', true),
|
||||
('Mandel', 'nose', true), ('Mandel', 'taste', true),
|
||||
('Sahnebonbon', 'nose', true), ('Sahnebonbon', 'taste', true),
|
||||
|
||||
-- WÜRZIG & NUSSIG (SPICY & NUTTY)
|
||||
('Eiche', 'nose', true), ('Eiche', 'taste', true),
|
||||
('Zimt', 'nose', true), ('Zimt', 'taste', true),
|
||||
('Pfeffer', 'nose', true), ('Pfeffer', 'taste', true),
|
||||
('Muskatnuss', 'nose', true), ('Muskatnuss', 'taste', true),
|
||||
('Ingwer', 'nose', true), ('Ingwer', 'taste', true),
|
||||
('Nelke', 'nose', true), ('Nelke', 'taste', true),
|
||||
('Walnuss', 'nose', true), ('Walnuss', 'taste', true),
|
||||
('Haselnuss', 'nose', true), ('Haselnuss', 'taste', true),
|
||||
('Geröstete Nüsse', 'nose', true), ('Geröstete Nüsse', 'taste', true),
|
||||
|
||||
-- RAUCHIG & TORFIG (PEATY & SMOKY)
|
||||
('Lagerfeuer', 'nose', true), ('Lagerfeuer', 'taste', true),
|
||||
('Holzkohle', 'nose', true), ('Holzkohle', 'taste', true),
|
||||
('Torfrauch', 'nose', true), ('Torfrauch', 'taste', true),
|
||||
('Asche', 'nose', true), ('Asche', 'taste', true),
|
||||
('Jod', 'nose', true), ('Jod', 'taste', true),
|
||||
('Medizinisch', 'nose', true), ('Medizinisch', 'taste', true),
|
||||
('Teer', 'nose', true), ('Teer', 'taste', true),
|
||||
('Asphalt', 'nose', true), ('Asphalt', 'taste', true),
|
||||
('Geräucherter Schinken', 'nose', true), ('Geräucherter Schinken', 'taste', true),
|
||||
('Speck', 'nose', true), ('Speck', 'taste', true),
|
||||
('Grillfleisch', 'nose', true), ('Grillfleisch', 'taste', true),
|
||||
|
||||
-- MARITIM & SALZIG (COASTAL)
|
||||
('Meersalz', 'nose', true), ('Meersalz', 'taste', true),
|
||||
('Salzlake', 'nose', true), ('Salzlake', 'taste', true),
|
||||
('Seetang', 'nose', true), ('Seetang', 'taste', true),
|
||||
('Algen', 'nose', true), ('Algen', 'taste', true),
|
||||
('Austern', 'nose', true), ('Austern', 'taste', true),
|
||||
('Meeresbrise', 'nose', true), ('Meeresbrise', 'taste', true),
|
||||
|
||||
-- FLORAL & KRÄUTER (FLORAL & HERBAL)
|
||||
('Heidekraut', 'nose', true), ('Heidekraut', 'taste', true),
|
||||
('Gras', 'nose', true), ('Gras', 'taste', true),
|
||||
('Heu', 'nose', true), ('Heu', 'taste', true),
|
||||
('Minze', 'nose', true), ('Minze', 'taste', true),
|
||||
('Menthol', 'nose', true), ('Menthol', 'taste', true),
|
||||
('Eukalyptus', 'nose', true), ('Eukalyptus', 'taste', true),
|
||||
('Tabak', 'nose', true), ('Tabak', 'taste', true),
|
||||
('Leder', 'nose', true), ('Leder', 'taste', true),
|
||||
('Tee', 'nose', true), ('Tee', 'taste', true),
|
||||
|
||||
-- FINISH DAUER
|
||||
('Kurz & Knackig', 'finish', true),
|
||||
('Mittellang', 'finish', true),
|
||||
('Lang anhaltend', 'finish', true),
|
||||
('Ewig', 'finish', true),
|
||||
|
||||
-- TEXTUR & GEFÜHL
|
||||
('Ölig', 'texture', true),
|
||||
('Viskos', 'texture', true),
|
||||
('Trocken', 'texture', true),
|
||||
('Adstringierend', 'texture', true),
|
||||
('Wärmend', 'texture', true),
|
||||
('Scharf', 'texture', true),
|
||||
('Beißend', 'texture', true),
|
||||
('Weich', 'texture', true),
|
||||
('Samtig', 'texture', true),
|
||||
('Wässrig', 'texture', true)
|
||||
ON CONFLICT (name, category) DO NOTHING;
|
||||
Reference in New Issue
Block a user