From 0ba695f1595b5bcf88c6d594d42dc555d40b364f Mon Sep 17 00:00:00 2001 From: Pantry Lead Agent Date: Wed, 25 Feb 2026 01:22:14 +0000 Subject: [PATCH 1/6] feat: add expiry date and low-stock threshold columns (#63 #67) --- .../migrations/006_add_expiry_lowstock.sql | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 supabase/migrations/006_add_expiry_lowstock.sql diff --git a/supabase/migrations/006_add_expiry_lowstock.sql b/supabase/migrations/006_add_expiry_lowstock.sql new file mode 100644 index 0000000..2f04b1b --- /dev/null +++ b/supabase/migrations/006_add_expiry_lowstock.sql @@ -0,0 +1,22 @@ +-- Migration: Add expiry date and low-stock threshold tracking +-- Issues: #63 (expiry tracking), #67 (low-stock threshold) +-- Created: 2026-02-25 + +-- Add expires_at column for expiry date tracking +ALTER TABLE pantry_items +ADD COLUMN expires_at TIMESTAMP WITH TIME ZONE DEFAULT NULL; + +-- Add low_stock_threshold column for low-stock alerts +ALTER TABLE pantry_items +ADD COLUMN low_stock_threshold NUMERIC(10,2) DEFAULT NULL; + +-- Add comments for documentation +COMMENT ON COLUMN pantry_items.expires_at IS 'Optional expiration date for the item. Null means no expiry tracking.'; +COMMENT ON COLUMN pantry_items.low_stock_threshold IS 'Minimum quantity threshold. Item is considered low-stock when quantity <= threshold. Null means no threshold set.'; + +-- Create index for efficient expiry queries (finding items expiring soon) +CREATE INDEX idx_pantry_items_expires_at ON pantry_items(expires_at) WHERE expires_at IS NOT NULL; + +-- Create index for efficient low-stock queries +CREATE INDEX idx_pantry_items_low_stock ON pantry_items(quantity, low_stock_threshold) +WHERE low_stock_threshold IS NOT NULL; -- 2.49.1 From c5870f9e6ff75f94c36bc11b80d74224d09c4f96 Mon Sep 17 00:00:00 2001 From: Pantry Lead Agent Date: Wed, 25 Feb 2026 01:22:51 +0000 Subject: [PATCH 2/6] fix: correct table name to inventory_items in migration --- .../migrations/006_add_expiry_lowstock.sql | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/supabase/migrations/006_add_expiry_lowstock.sql b/supabase/migrations/006_add_expiry_lowstock.sql index 2f04b1b..d2bfa4f 100644 --- a/supabase/migrations/006_add_expiry_lowstock.sql +++ b/supabase/migrations/006_add_expiry_lowstock.sql @@ -2,21 +2,25 @@ -- Issues: #63 (expiry tracking), #67 (low-stock threshold) -- Created: 2026-02-25 --- Add expires_at column for expiry date tracking -ALTER TABLE pantry_items +-- Note: expiry_date already exists as DATE type. Adding expires_at as TIMESTAMPTZ for consistency +-- and low_stock_threshold for threshold tracking. + +-- Add expires_at column for precise expiry date/time tracking (complementing existing expiry_date) +-- We'll keep both: expiry_date (DATE) for simple day-based expiry, expires_at (TIMESTAMPTZ) for precise tracking +ALTER TABLE inventory_items ADD COLUMN expires_at TIMESTAMP WITH TIME ZONE DEFAULT NULL; -- Add low_stock_threshold column for low-stock alerts -ALTER TABLE pantry_items +ALTER TABLE inventory_items ADD COLUMN low_stock_threshold NUMERIC(10,2) DEFAULT NULL; -- Add comments for documentation -COMMENT ON COLUMN pantry_items.expires_at IS 'Optional expiration date for the item. Null means no expiry tracking.'; -COMMENT ON COLUMN pantry_items.low_stock_threshold IS 'Minimum quantity threshold. Item is considered low-stock when quantity <= threshold. Null means no threshold set.'; +COMMENT ON COLUMN inventory_items.expires_at IS 'Optional precise expiration timestamp. Complements expiry_date for items needing time-specific expiry.'; +COMMENT ON COLUMN inventory_items.low_stock_threshold IS 'Minimum quantity threshold. Item is considered low-stock when quantity <= threshold. Null means no threshold set.'; -- Create index for efficient expiry queries (finding items expiring soon) -CREATE INDEX idx_pantry_items_expires_at ON pantry_items(expires_at) WHERE expires_at IS NOT NULL; +CREATE INDEX idx_inventory_items_expires_at ON inventory_items(expires_at) WHERE expires_at IS NOT NULL; -- Create index for efficient low-stock queries -CREATE INDEX idx_pantry_items_low_stock ON pantry_items(quantity, low_stock_threshold) +CREATE INDEX idx_inventory_items_low_stock ON inventory_items(quantity, low_stock_threshold) WHERE low_stock_threshold IS NOT NULL; -- 2.49.1 From 76a229952f1493bc34e6c6d063e9839bb043eecb Mon Sep 17 00:00:00 2001 From: Pantry Lead Agent Date: Wed, 25 Feb 2026 01:23:00 +0000 Subject: [PATCH 3/6] feat: add expires_at and low_stock_threshold to type definitions (#63 #67) --- app/types/database.types.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/types/database.types.ts b/app/types/database.types.ts index 2a30c5b..5d3a8ff 100644 --- a/app/types/database.types.ts +++ b/app/types/database.types.ts @@ -26,6 +26,8 @@ export interface Database { quantity: number unit_id: string expiry_date: string | null + expires_at: string | null + low_stock_threshold: number | null notes: string | null added_by: string created_at: string @@ -38,6 +40,8 @@ export interface Database { quantity: number unit_id: string expiry_date?: string | null + expires_at?: string | null + low_stock_threshold?: number | null notes?: string | null added_by: string created_at?: string @@ -50,6 +54,8 @@ export interface Database { quantity?: number unit_id?: string expiry_date?: string | null + expires_at?: string | null + low_stock_threshold?: number | null notes?: string | null added_by?: string created_at?: string -- 2.49.1 From 1ed51c3667834d1cdbe5973cdd0e694ac41d33e3 Mon Sep 17 00:00:00 2001 From: Pantry Lead Agent Date: Wed, 25 Feb 2026 01:23:23 +0000 Subject: [PATCH 4/6] feat: add low-stock threshold field to AddItemForm (#67) --- app/components/inventory/AddItemForm.vue | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/components/inventory/AddItemForm.vue b/app/components/inventory/AddItemForm.vue index cf16d44..310cbd2 100644 --- a/app/components/inventory/AddItemForm.vue +++ b/app/components/inventory/AddItemForm.vue @@ -57,6 +57,21 @@ /> + + + + + { quantity: form.quantity, unit_id: form.unit_id, expiry_date: form.expiry_date || null, + low_stock_threshold: form.low_stock_threshold, notes: form.notes.trim() || null }) -- 2.49.1 From bd000649e3561dcff2fda0fa501b17c4688a31a0 Mon Sep 17 00:00:00 2001 From: Pantry Lead Agent Date: Wed, 25 Feb 2026 01:23:40 +0000 Subject: [PATCH 5/6] feat: add low-stock threshold field to EditItemModal (#67) --- app/components/inventory/EditItemModal.vue | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/components/inventory/EditItemModal.vue b/app/components/inventory/EditItemModal.vue index 2d4e270..baa2115 100644 --- a/app/components/inventory/EditItemModal.vue +++ b/app/components/inventory/EditItemModal.vue @@ -55,6 +55,21 @@ /> + + + + + props.item, (newItem) => { form.quantity = Number(newItem.quantity) form.unit_id = newItem.unit_id form.expiry_date = newItem.expiry_date || '' + form.low_stock_threshold = newItem.low_stock_threshold || null form.notes = newItem.notes || '' isOpen.value = true } @@ -168,6 +185,7 @@ const handleSubmit = async () => { quantity: form.quantity, unit_id: form.unit_id, expiry_date: form.expiry_date || null, + low_stock_threshold: form.low_stock_threshold, notes: form.notes.trim() || null }) -- 2.49.1 From 8a9f8f7fdd9a487aeead9a3c7e6fcf54a18d3ed8 Mon Sep 17 00:00:00 2001 From: Pantry Lead Agent Date: Wed, 25 Feb 2026 01:24:07 +0000 Subject: [PATCH 6/6] feat: add low-stock visual indicator to InventoryCard (#67) --- app/components/inventory/InventoryCard.vue | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/components/inventory/InventoryCard.vue b/app/components/inventory/InventoryCard.vue index 242fd0d..b63fbd1 100644 --- a/app/components/inventory/InventoryCard.vue +++ b/app/components/inventory/InventoryCard.vue @@ -72,6 +72,18 @@ {{ expiryText }} + + +
+ + + Low stock ({{ item.quantity }}/{{ item.low_stock_threshold }}) + +
@@ -145,4 +157,10 @@ const expiryText = computed(() => { if (daysUntilExpiry.value === 1) return 'Expires tomorrow' return `Expires in ${daysUntilExpiry.value} days` }) + +// Low stock detection +const isLowStock = computed(() => { + if (!props.item.low_stock_threshold) return false + return Number(props.item.quantity) <= Number(props.item.low_stock_threshold) +}) -- 2.49.1