feat: Fase 2a — shopping lists CRUD

DB: shopping_lists + shopping_items tables with full RLS, pg_cron jobs
(archive completed lists after 7 days, purge trash after 7 days).
item_frequency table with SECURITY DEFINER trigger that normalises and
upserts on every shopping_items INSERT.

Frontend: /lists overview (featured card + 2-col grid + trash toggle),
/lists/[id] detail (qty stepper, inline edit, swipe-to-reveal-delete,
drag & drop reorder via svelte-dnd-action, ItemSuggestions chips).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-12 22:25:31 +02:00
parent ce1bcfb7a6
commit 3af1276c15
11 changed files with 1609 additions and 12 deletions

View File

@@ -7,6 +7,7 @@ export type Json = string | number | boolean | null | { [key: string]: Json | un
export type LanguageCode = 'en' | 'es';
export type AvatarTypeEnum = 'initials' | 'emoji' | 'upload';
export type MemberRoleEnum = 'admin' | 'member' | 'guest';
export type ListStatusEnum = 'active' | 'completed' | 'archived';
export interface Database {
public: {
@@ -161,6 +162,102 @@ export interface Database {
}
];
};
shopping_lists: {
Row: {
id: string;
collective_id: string;
name: string;
status: ListStatusEnum;
created_by: string;
created_at: string;
completed_at: string | null;
deleted_at: string | null;
};
Insert: {
id?: string;
collective_id: string;
name: string;
status?: ListStatusEnum;
created_by: string;
created_at?: string;
completed_at?: string | null;
deleted_at?: string | null;
};
Update: {
id?: string;
collective_id?: string;
name?: string;
status?: ListStatusEnum;
created_by?: string;
created_at?: string;
completed_at?: string | null;
deleted_at?: string | null;
};
Relationships: [];
};
shopping_items: {
Row: {
id: string;
list_id: string;
name: string;
quantity: number | null;
unit: string | null;
is_checked: boolean;
checked_by: string | null;
checked_at: string | null;
sort_order: number;
created_by: string;
created_at: string;
};
Insert: {
id?: string;
list_id: string;
name: string;
quantity?: number | null;
unit?: string | null;
is_checked?: boolean;
checked_by?: string | null;
checked_at?: string | null;
sort_order?: number;
created_by: string;
created_at?: string;
};
Update: {
id?: string;
list_id?: string;
name?: string;
quantity?: number | null;
unit?: string | null;
is_checked?: boolean;
checked_by?: string | null;
checked_at?: string | null;
sort_order?: number;
created_by?: string;
created_at?: string;
};
Relationships: [];
};
item_frequency: {
Row: {
collective_id: string;
name: string;
use_count: number;
last_used_at: string;
};
Insert: {
collective_id: string;
name: string;
use_count?: number;
last_used_at?: string;
};
Update: {
collective_id?: string;
name?: string;
use_count?: number;
last_used_at?: string;
};
Relationships: [];
};
};
Views: Record<string, never>;
Functions: {
@@ -185,6 +282,7 @@ export interface Database {
language_code: LanguageCode;
avatar_type: AvatarTypeEnum;
member_role: MemberRoleEnum;
list_status: ListStatusEnum;
};
};
}

View File

@@ -78,7 +78,6 @@ export interface ShoppingItem {
sort_order: number;
created_by: string;
created_at: string;
deleted_at: string | null;
}
export interface ItemFrequency {