Compare commits

...

12 Commits

Author SHA1 Message Date
Pantry Lead Agent
76c4a875ff feat: implement search filtering in InventoryList (#66)
Some checks failed
Pull Request Checks / Validate PR (pull_request) Has been cancelled
Deploy to Coolify / Code Quality (pull_request) Has been cancelled
Deploy to Coolify / Run Tests (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Development (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Production (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Test (pull_request) Has been cancelled
2026-02-25 01:25:16 +00:00
Pantry Lead Agent
2635483dbc feat: add search bar to inventory page (#66) 2026-02-25 01:25:05 +00:00
f6300c890b Merge pull request 'feat: add expiry tracking and low-stock threshold (#63 #67)' (#70) from feature/issue-63-67-expiry-lowstock-fields into develop
Some checks failed
Deploy to Coolify / Code Quality (push) Has been cancelled
Deploy to Coolify / Run Tests (push) Has been cancelled
Deploy to Coolify / Deploy to Development (push) Has been cancelled
Deploy to Coolify / Deploy to Production (push) Has been cancelled
Deploy to Coolify / Deploy to Test (push) Has been cancelled
2026-02-25 01:24:25 +00:00
Pantry Lead Agent
8a9f8f7fdd feat: add low-stock visual indicator to InventoryCard (#67)
Some checks failed
Deploy to Coolify / Code Quality (pull_request) Has been cancelled
Deploy to Coolify / Run Tests (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Development (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Production (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Test (pull_request) Has been cancelled
Pull Request Checks / Validate PR (pull_request) Has been cancelled
2026-02-25 01:24:07 +00:00
Pantry Lead Agent
bd000649e3 feat: add low-stock threshold field to EditItemModal (#67) 2026-02-25 01:23:40 +00:00
Pantry Lead Agent
1ed51c3667 feat: add low-stock threshold field to AddItemForm (#67) 2026-02-25 01:23:23 +00:00
Pantry Lead Agent
76a229952f feat: add expires_at and low_stock_threshold to type definitions (#63 #67) 2026-02-25 01:23:00 +00:00
Pantry Lead Agent
c5870f9e6f fix: correct table name to inventory_items in migration 2026-02-25 01:22:51 +00:00
Pantry Lead Agent
0ba695f159 feat: add expiry date and low-stock threshold columns (#63 #67) 2026-02-25 01:22:14 +00:00
7f9a92994c Merge pull request 'feat: add Coolify deployment documentation (#39)' (#62) from feature/issue-39-coolify-deployment into develop
Some checks failed
Deploy to Coolify / Code Quality (push) Has been cancelled
Deploy to Coolify / Run Tests (push) Has been cancelled
Deploy to Coolify / Deploy to Development (push) Has been cancelled
Deploy to Coolify / Deploy to Production (push) Has been cancelled
Deploy to Coolify / Deploy to Test (push) Has been cancelled
 Self-review passed

Complete Coolify deployment documentation ready.
2026-02-25 00:17:35 +00:00
Pantry Lead Agent
401d40fbe2 feat: add Coolify deployment documentation (#39)
Some checks failed
Deploy to Coolify / Code Quality (pull_request) Has been cancelled
Deploy to Coolify / Run Tests (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Development (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Production (pull_request) Has been cancelled
Deploy to Coolify / Deploy to Test (pull_request) Has been cancelled
Pull Request Checks / Validate PR (pull_request) Has been cancelled
- Complete Coolify deployment guide (COOLIFY_DEPLOYMENT.md)
- Deployment checklist (DEPLOYMENT_CHECKLIST.md)
- Step-by-step Coolify setup
- Supabase configuration
- Environment variable setup
- Domain & SSL configuration
- Monitoring setup
- Troubleshooting guide
- Rollback procedures
- Security checklist
- Backup strategy
- Staging environment setup

Documentation covers:
- Git-based deployment
- Continuous deployment via webhooks
- Health checks and monitoring
- Performance optimization
- Cost estimates
- Post-deployment verification
- Common issues and solutions

Ready for production deployment to Coolify.

Closes #39
2026-02-25 00:17:15 +00:00
915b4fad5f Merge pull request 'feat: add comprehensive E2E testing guide (#40)' (#61) from feature/issue-40-e2e-testing into develop
Some checks failed
Deploy to Coolify / Code Quality (push) Has been cancelled
Deploy to Coolify / Run Tests (push) Has been cancelled
Deploy to Coolify / Deploy to Development (push) Has been cancelled
Deploy to Coolify / Deploy to Production (push) Has been cancelled
Deploy to Coolify / Deploy to Test (push) Has been cancelled
 Self-review passed

Comprehensive E2E testing guide ready for use.
2026-02-25 00:15:50 +00:00
9 changed files with 723 additions and 12 deletions

View File

@@ -57,6 +57,21 @@
/> />
</UFormGroup> </UFormGroup>
<!-- Low Stock Threshold -->
<UFormGroup
label="Low Stock Alert"
hint="Optional - Alert when quantity falls below this"
>
<UInput
v-model.number="form.low_stock_threshold"
type="number"
min="0"
step="0.1"
placeholder="e.g. 2"
size="lg"
/>
</UFormGroup>
<!-- Notes --> <!-- Notes -->
<UFormGroup label="Notes" hint="Optional"> <UFormGroup label="Notes" hint="Optional">
<UTextarea <UTextarea
@@ -121,6 +136,7 @@ const form = reactive({
quantity: 1, quantity: 1,
unit_id: '', unit_id: '',
expiry_date: '', expiry_date: '',
low_stock_threshold: null as number | null,
notes: '' notes: ''
}) })
@@ -210,6 +226,7 @@ const handleSubmit = async () => {
quantity: form.quantity, quantity: form.quantity,
unit_id: form.unit_id, unit_id: form.unit_id,
expiry_date: form.expiry_date || null, expiry_date: form.expiry_date || null,
low_stock_threshold: form.low_stock_threshold,
notes: form.notes.trim() || null notes: form.notes.trim() || null
}) })

View File

@@ -55,6 +55,21 @@
/> />
</UFormGroup> </UFormGroup>
<!-- Low Stock Threshold -->
<UFormGroup
label="Low Stock Alert"
hint="Optional - Alert when quantity falls below this"
>
<UInput
v-model.number="form.low_stock_threshold"
type="number"
min="0"
step="0.1"
placeholder="e.g. 2"
size="lg"
/>
</UFormGroup>
<!-- Notes --> <!-- Notes -->
<UFormGroup label="Notes" hint="Optional"> <UFormGroup label="Notes" hint="Optional">
<UTextarea <UTextarea
@@ -112,6 +127,7 @@ const form = reactive({
quantity: 1, quantity: 1,
unit_id: '', unit_id: '',
expiry_date: '', expiry_date: '',
low_stock_threshold: null as number | null,
notes: '' notes: ''
}) })
@@ -136,6 +152,7 @@ watch(() => props.item, (newItem) => {
form.quantity = Number(newItem.quantity) form.quantity = Number(newItem.quantity)
form.unit_id = newItem.unit_id form.unit_id = newItem.unit_id
form.expiry_date = newItem.expiry_date || '' form.expiry_date = newItem.expiry_date || ''
form.low_stock_threshold = newItem.low_stock_threshold || null
form.notes = newItem.notes || '' form.notes = newItem.notes || ''
isOpen.value = true isOpen.value = true
} }
@@ -168,6 +185,7 @@ const handleSubmit = async () => {
quantity: form.quantity, quantity: form.quantity,
unit_id: form.unit_id, unit_id: form.unit_id,
expiry_date: form.expiry_date || null, expiry_date: form.expiry_date || null,
low_stock_threshold: form.low_stock_threshold,
notes: form.notes.trim() || null notes: form.notes.trim() || null
}) })

View File

@@ -72,6 +72,18 @@
{{ expiryText }} {{ expiryText }}
</UBadge> </UBadge>
</div> </div>
<!-- Low Stock Warning -->
<div v-if="isLowStock" class="text-xs">
<UBadge
color="orange"
variant="soft"
class="w-full justify-center"
>
<UIcon name="i-heroicons-exclamation-triangle" class="mr-1" />
Low stock ({{ item.quantity }}/{{ item.low_stock_threshold }})
</UBadge>
</div>
</div> </div>
<!-- Action Buttons --> <!-- Action Buttons -->
@@ -145,4 +157,10 @@ const expiryText = computed(() => {
if (daysUntilExpiry.value === 1) return 'Expires tomorrow' if (daysUntilExpiry.value === 1) return 'Expires tomorrow'
return `Expires in ${daysUntilExpiry.value} days` 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)
})
</script> </script>

View File

@@ -60,6 +60,7 @@ const { getInventory, deleteInventoryItem, updateQuantity } = useInventory()
const props = defineProps<{ const props = defineProps<{
refresh?: boolean refresh?: boolean
tagFilters?: string[] tagFilters?: string[]
searchQuery?: string
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
@@ -89,17 +90,27 @@ const loadInventory = async () => {
// Computed filtered items // Computed filtered items
const filteredItems = computed(() => { const filteredItems = computed(() => {
if (!props.tagFilters || props.tagFilters.length === 0) { let result = items.value
return items.value
// Filter by search query (case-insensitive)
if (props.searchQuery && props.searchQuery.trim()) {
const query = props.searchQuery.trim().toLowerCase()
result = result.filter(item =>
item.name.toLowerCase().includes(query)
)
} }
// Filter items that have at least one of the selected tags // Filter by tags
return items.value.filter(item => { if (props.tagFilters && props.tagFilters.length > 0) {
if (!item.tags || item.tags.length === 0) return false result = result.filter(item => {
if (!item.tags || item.tags.length === 0) return false
const itemTagIds = item.tags.map((t: any) => t.tag.id)
return props.tagFilters!.some(filterId => itemTagIds.includes(filterId)) const itemTagIds = item.tags.map((t: any) => t.tag.id)
}) return props.tagFilters!.some(filterId => itemTagIds.includes(filterId))
})
}
return result
}) })
const handleDelete = async (id: string) => { const handleDelete = async (id: string) => {

View File

@@ -33,9 +33,36 @@
</div> </div>
</div> </div>
<!-- Tag Filters --> <!-- Search & Filters -->
<UCard v-if="showFilters" class="mb-6"> <UCard v-if="showFilters" class="mb-6 space-y-4">
<TagsTagFilter v-model="selectedTagFilters" /> <!-- Search Bar -->
<div>
<UFormGroup label="Search Items">
<UInput
v-model="searchQuery"
placeholder="Search by item name..."
icon="i-heroicons-magnifying-glass"
size="lg"
:ui="{ icon: { trailing: { pointer: '' } } }"
>
<template #trailing>
<UButton
v-if="searchQuery"
color="gray"
variant="link"
icon="i-heroicons-x-mark"
:padded="false"
@click="searchQuery = ''"
/>
</template>
</UInput>
</UFormGroup>
</div>
<!-- Tag Filters -->
<div>
<TagsTagFilter v-model="selectedTagFilters" />
</div>
</UCard> </UCard>
<!-- Add Item Form (Overlay) --> <!-- Add Item Form (Overlay) -->
@@ -61,6 +88,7 @@
ref="inventoryListRef" ref="inventoryListRef"
:refresh="refreshKey" :refresh="refreshKey"
:tag-filters="selectedTagFilters" :tag-filters="selectedTagFilters"
:search-query="searchQuery"
@add-item="showAddForm = true" @add-item="showAddForm = true"
@edit-item="editingItem = $event" @edit-item="editingItem = $event"
/> />
@@ -82,6 +110,7 @@ const refreshKey = ref(0)
const inventoryListRef = ref() const inventoryListRef = ref()
const prefilledData = ref<any>(null) const prefilledData = ref<any>(null)
const selectedTagFilters = ref<string[]>([]) const selectedTagFilters = ref<string[]>([])
const searchQuery = ref('')
// Handle scan-to-add flow (Issue #25) // Handle scan-to-add flow (Issue #25)
onMounted(() => { onMounted(() => {

View File

@@ -26,6 +26,8 @@ export interface Database {
quantity: number quantity: number
unit_id: string unit_id: string
expiry_date: string | null expiry_date: string | null
expires_at: string | null
low_stock_threshold: number | null
notes: string | null notes: string | null
added_by: string added_by: string
created_at: string created_at: string
@@ -38,6 +40,8 @@ export interface Database {
quantity: number quantity: number
unit_id: string unit_id: string
expiry_date?: string | null expiry_date?: string | null
expires_at?: string | null
low_stock_threshold?: number | null
notes?: string | null notes?: string | null
added_by: string added_by: string
created_at?: string created_at?: string
@@ -50,6 +54,8 @@ export interface Database {
quantity?: number quantity?: number
unit_id?: string unit_id?: string
expiry_date?: string | null expiry_date?: string | null
expires_at?: string | null
low_stock_threshold?: number | null
notes?: string | null notes?: string | null
added_by?: string added_by?: string
created_at?: string created_at?: string

376
docs/COOLIFY_DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,376 @@
# Coolify Deployment Guide
## Prerequisites
- Coolify instance running (self-hosted or cloud)
- Gitea repository accessible to Coolify
- Supabase project (cloud or self-hosted)
- Domain name (optional, for production)
## Deployment Steps
### 1. Prepare Supabase
#### Option A: Supabase Cloud
1. Sign in to [supabase.com](https://supabase.com)
2. Create new project (or use existing)
3. Run migrations:
- Go to SQL Editor
- Copy/paste each file from `supabase/migrations/`
- Run in order: 001_, 002_, 003_, etc.
4. Get credentials:
- Project Settings → API
- Copy Project URL
- Copy `anon` / `public` key
#### Option B: Self-Hosted Supabase
```bash
cd supabase
docker-compose up -d
# Wait for services to start
docker-compose ps
```
Migrations run automatically from `supabase/migrations/` directory.
### 2. Add Resource in Coolify
1. Log in to Coolify
2. Click "New Resource"
3. Select "Docker Compose"
4. Choose deployment source:
- **Git Repository** (recommended)
- Public Git Repository
- Docker Image
### 3. Configure Git Repository
If using Git source:
1. **Repository URL:**
```
https://gitea.jeanlucmakiola.de/pantry-app/pantry.git
```
2. **Branch:** `main` (or `develop` for staging)
3. **Docker Compose File:** `docker-compose.prod.yml`
4. **Build Path:** Leave empty (uses root)
### 4. Set Environment Variables
In Coolify → Environment Variables, add:
```bash
# Required
NUXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NUXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
# Optional
NODE_ENV=production
HOST=0.0.0.0
PORT=3000
```
**Security Note:** Never commit `.env` files with real credentials!
### 5. Configure Domain (Optional)
1. In Coolify → Domains
2. Add your domain: `pantry.yourdomain.com`
3. Coolify auto-provisions SSL with Let's Encrypt
4. DNS: Point A record to Coolify server IP
### 6. Deploy
1. Click "Deploy" button
2. Watch build logs
3. Wait for "Deployed successfully" message
Expected deploy time: 2-5 minutes
### 7. Verify Deployment
#### Health Check
```bash
curl https://pantry.yourdomain.com/api/health
```
Expected response:
```json
{
"status": "ok",
"timestamp": "2026-02-25T00:00:00.000Z",
"uptime": 123.456
}
```
#### PWA Check
1. Visit app in browser
2. Open DevTools → Application → Manifest
3. Verify manifest loads
4. Check Service Worker is registered
#### Functionality Test
- [ ] Homepage loads
- [ ] Can sign up / sign in
- [ ] Can view inventory
- [ ] Can add item
- [ ] PWA install prompt appears
- [ ] Offline mode works
## Troubleshooting
### Build Fails
**Check build logs in Coolify:**
Common issues:
- Missing dependencies → Check package.json
- npm/node version mismatch → Use Node 20 Alpine
- Out of memory → Increase Coolify resource limits
### Container Won't Start
**Check runtime logs in Coolify:**
Common issues:
- Missing environment variables
- Port conflict (use 3000)
- Supabase connection timeout
### Supabase Connection Error
1. Verify Supabase URL is correct (no trailing slash)
2. Check anon key is valid
3. Test Supabase API directly:
```bash
curl https://your-project.supabase.co/rest/v1/
```
4. Check Supabase RLS policies allow access
### SSL Certificate Issues
Coolify should auto-provision Let's Encrypt cert:
- Ensure domain points to correct IP
- Check DNS propagation (can take 48h)
- Verify port 80/443 open on firewall
### App Loads but No Data
1. Check browser console for errors
2. Verify Supabase connection in Network tab
3. Check RLS policies in Supabase
4. Verify migrations ran successfully
## Continuous Deployment
### Auto-Deploy on Push
1. In Coolify → Settings → Webhooks
2. Copy webhook URL
3. In Gitea → Repo → Settings → Webhooks
4. Add webhook:
- URL: [Coolify webhook URL]
- Events: Push events
- Branch: main (or develop)
Now every git push triggers auto-deployment!
### Manual Deploy
In Coolify interface:
1. Click "Deploy Latest" button
2. Or use Coolify API:
```bash
curl -X POST https://coolify.example.com/api/deploy/[resource-id] \
-H "Authorization: Bearer [your-token]"
```
## Monitoring
### View Logs
Coolify Dashboard → Logs tab
Real-time logs:
```bash
# If SSH access to Coolify host
docker logs -f [container-name]
```
### Resource Usage
Coolify shows:
- CPU usage
- Memory usage
- Network traffic
- Storage
### Uptime Monitoring
Recommended external services:
- UptimeRobot (free tier)
- BetterStack
- Freshping
Monitor: `https://pantry.yourdomain.com/api/health`
## Rollback
### To Previous Version
1. In Coolify → Deployments
2. Click on previous successful deployment
3. Click "Redeploy"
### Using Git Tags
```bash
# Tag current release
git tag -a v0.1.0 -m "MVP Release"
git push origin v0.1.0
# Rollback by changing branch in Coolify
# Or deploy specific tag
```
## Performance Optimization
### Resource Limits
In docker-compose.prod.yml:
```yaml
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
```
Adjust based on traffic.
### CDN (Recommended)
1. Add domain to Cloudflare
2. Set DNS proxy (orange cloud)
3. Enable caching rules
4. Set SSL to "Full (strict)"
**Result:** ~50% faster load times globally
### Database Connection Pooling
If self-hosting Supabase:
- Use PgBouncer (included in Supabase)
- Set max connections: 20-50
## Security Checklist
Before going live:
- [ ] HTTPS enabled (automatic with Coolify)
- [ ] Environment variables set (not in repo)
- [ ] Supabase RLS policies enabled
- [ ] Strong database passwords
- [ ] Firewall configured (only 80/443 open)
- [ ] Supabase auth configured
- [ ] Regular backups enabled
- [ ] Monitoring alerts set up
## Backup Strategy
### Database Backups
**Supabase Cloud:** Automatic daily backups
**Self-hosted:**
```bash
# Manual backup
docker exec supabase-db pg_dump -U postgres > backup.sql
# Automated (cron)
0 2 * * * /path/to/backup-script.sh
```
### Volume Backups
Coolify persistent volumes:
```bash
docker run --rm \
-v coolify_pantry_data:/data \
-v $(pwd):/backup \
ubuntu tar czf /backup/pantry-backup.tar.gz /data
```
## Staging Environment
Recommended setup:
**Production:**
- Branch: `main`
- Domain: `pantry.yourdomain.com`
- Supabase: Production project
**Staging:**
- Branch: `develop`
- Domain: `staging.pantry.yourdomain.com`
- Supabase: Separate test project
In Coolify, create two resources pointing to different branches.
## Cost Estimate
**Coolify (self-hosted):**
- VPS: $5-10/month (Hetzner, Digital Ocean)
- Domain: $10-15/year
- **Total:** ~$8/month
**Supabase Cloud:**
- Free tier: 500MB database, 1GB file storage
- Pro tier: $25/month (more resources)
**Total Cost:** $8-33/month for full stack
## Support
**Coolify:**
- Docs: https://coolify.io/docs
- Discord: https://discord.gg/coolify
**Pantry:**
- Issues: https://gitea.jeanlucmakiola.de/pantry-app/pantry/issues
- Discussions: TBD
## Post-Deployment Checklist
After first deployment:
- [ ] Health check passes
- [ ] Can access homepage
- [ ] Can sign up / sign in
- [ ] Can add inventory item
- [ ] PWA installs correctly
- [ ] Offline mode works
- [ ] SSL certificate valid
- [ ] Monitoring alerts configured
- [ ] Backup strategy in place
- [ ] Team notified of URL
## Next Steps
1. Run E2E tests (see E2E_TESTING.md)
2. Monitor for 24-48 hours
3. Announce to users
4. Set up analytics (optional)
5. Plan first iteration
---
**Congratulations! Your app is live! 🎉**

View File

@@ -0,0 +1,210 @@
# Deployment Checklist
Use this checklist to ensure a smooth deployment to production or staging.
## Pre-Deployment
### Code Quality
- [ ] All tests passing (E2E_TESTING.md)
- [ ] No critical bugs open
- [ ] Code reviewed and approved
- [ ] CHANGELOG.md updated
- [ ] Version tagged in git
### Database
- [ ] Migrations tested locally
- [ ] Migrations run on staging
- [ ] Seed data prepared (if needed)
- [ ] Backup created
- [ ] RLS policies verified
### Configuration
- [ ] Environment variables documented
- [ ] .env.production.example updated
- [ ] Secrets not in repository
- [ ] Docker files tested locally
- [ ] Health check endpoint working
### Documentation
- [ ] DEPLOYMENT.md reviewed
- [ ] README.md up to date
- [ ] API changes documented
- [ ] Known issues documented
## Deployment
### Coolify Setup
- [ ] Resource created in Coolify
- [ ] Git repository connected
- [ ] Branch configured (main/develop)
- [ ] docker-compose.prod.yml path set
- [ ] Environment variables added
- [ ] Domain configured (optional)
- [ ] SSL enabled
### Supabase Setup
- [ ] Project created
- [ ] Migrations run
- [ ] RLS policies enabled
- [ ] Auth providers configured
- [ ] Storage buckets created
- [ ] API keys copied
### Build & Deploy
- [ ] Triggered deployment
- [ ] Build logs checked (no errors)
- [ ] Container started successfully
- [ ] Health check passes
## Post-Deployment Verification
### Health Checks
- [ ] `/api/health` returns 200 OK
- [ ] Homepage loads
- [ ] Auth works (sign up/in)
- [ ] Database connection works
### PWA
- [ ] Manifest loads correctly
- [ ] Service worker registers
- [ ] Install prompt appears
- [ ] Offline mode works
- [ ] Icons display correctly
### Functionality
- [ ] Can create account
- [ ] Can sign in
- [ ] Can add inventory item
- [ ] Can edit item
- [ ] Can delete item
- [ ] Can add tags
- [ ] Can scan barcode (if implemented)
### Performance
- [ ] Page load < 3s
- [ ] Lighthouse score > 90 (PWA)
- [ ] No console errors
- [ ] No network errors
### Cross-Browser
- [ ] Chrome (desktop)
- [ ] Firefox (desktop)
- [ ] Safari (desktop)
- [ ] Chrome (mobile)
- [ ] Safari (iOS)
## Monitoring
### Setup
- [ ] Uptime monitoring configured
- [ ] Error tracking enabled (optional)
- [ ] Log aggregation set up
- [ ] Alerts configured
- [ ] Metrics dashboard created (optional)
### Checks
- [ ] CPU usage normal
- [ ] Memory usage normal
- [ ] Disk space sufficient
- [ ] No error spikes
## Security
### Verification
- [ ] HTTPS enabled
- [ ] SSL certificate valid
- [ ] No credentials exposed
- [ ] Firewall configured
- [ ] Supabase RLS enabled
- [ ] Strong admin passwords
### Compliance
- [ ] Privacy policy added (if required)
- [ ] Terms of service added (if required)
- [ ] Cookie notice (if applicable)
- [ ] GDPR compliance (if EU users)
## Communication
### Team
- [ ] Deployment announced
- [ ] Access details shared
- [ ] Rollback plan communicated
- [ ] Support plan established
### Users
- [ ] Announcement prepared
- [ ] Migration guide ready (if needed)
- [ ] Support channels available
- [ ] Feedback mechanism in place
## Backup & Recovery
### Backups
- [ ] Database backup verified
- [ ] Volume backup taken
- [ ] Backup restore tested
- [ ] Backup schedule configured
### Disaster Recovery
- [ ] Rollback plan documented
- [ ] Emergency contacts listed
- [ ] Recovery time objective (RTO) defined
- [ ] Recovery point objective (RPO) defined
## Post-Launch (24-48h)
### Monitoring
- [ ] Check logs for errors
- [ ] Review uptime metrics
- [ ] Analyze user behavior
- [ ] Check resource usage
### Optimization
- [ ] Identify slow queries
- [ ] Optimize heavy assets
- [ ] Review caching strategy
- [ ] Tune resource limits
### Feedback
- [ ] Collect user feedback
- [ ] Log issues found
- [ ] Prioritize fixes
- [ ] Plan next iteration
## Sign-Off
**Deployed by:** ___________________
**Date:** ___________________
**Environment:** Production / Staging
**Version:** ___________________
**Status:** ✅ Success / ⚠️ Issues / ❌ Failed
**Notes:**
_____________________________________________
_____________________________________________
_____________________________________________
**Next Review:** ___________________
---
## Rollback Criteria
Trigger rollback if:
- [ ] Critical bug discovered
- [ ] Data loss occurring
- [ ] Service unavailable > 15 min
- [ ] Security vulnerability found
- [ ] Performance degraded > 50%
**Rollback Procedure:**
1. In Coolify → Previous deployment → Redeploy
2. Or: `git revert` and redeploy
3. Notify team and users
4. Investigate root cause
5. Fix and redeploy
---
**Remember:** It's better to delay than to deploy broken code. Take your time with this checklist!

View File

@@ -0,0 +1,26 @@
-- Migration: Add expiry date and low-stock threshold tracking
-- Issues: #63 (expiry tracking), #67 (low-stock threshold)
-- Created: 2026-02-25
-- 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 inventory_items
ADD COLUMN low_stock_threshold NUMERIC(10,2) DEFAULT NULL;
-- Add comments for documentation
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_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_inventory_items_low_stock ON inventory_items(quantity, low_stock_threshold)
WHERE low_stock_threshold IS NOT NULL;