Compare commits
2 Commits
f4b870f59c
...
5805be698b
| Author | SHA1 | Date | |
|---|---|---|---|
| 5805be698b | |||
|
|
1f21032194 |
335
DEV_SETUP.md
Normal file
335
DEV_SETUP.md
Normal file
@@ -0,0 +1,335 @@
|
||||
# Pantry - Local Development Setup
|
||||
|
||||
Self-hosted household pantry management app with barcode scanning.
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Docker** & **Docker Compose** (for Supabase backend)
|
||||
- **Bun** (for Nuxt frontend) - Install: `curl -fsSL https://bun.sh/install | bash`
|
||||
- **Git**
|
||||
|
||||
### 1. Clone & Setup
|
||||
|
||||
```bash
|
||||
git clone https://gitea.jeanlucmakiola.de/pantry-app/pantry.git
|
||||
cd pantry
|
||||
```
|
||||
|
||||
### 2. Start Supabase (Backend)
|
||||
|
||||
```bash
|
||||
# Start all Supabase services
|
||||
docker-compose up -d
|
||||
|
||||
# Wait ~10 seconds for services to initialize
|
||||
# Check status
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
**Services running:**
|
||||
- PostgreSQL: `localhost:5432`
|
||||
- Supabase API: `http://localhost:54321`
|
||||
- Supabase Studio: `http://localhost:54323` (admin UI)
|
||||
|
||||
### 3. Apply Database Migrations
|
||||
|
||||
The migrations are automatically applied on first startup via `/docker-entrypoint-initdb.d`.
|
||||
|
||||
To verify:
|
||||
```bash
|
||||
docker-compose exec db psql -U postgres -d postgres -c "\dt"
|
||||
```
|
||||
|
||||
You should see: `inventory_items`, `products`, `tags`, `units`, `item_tags`
|
||||
|
||||
### 4. Start Nuxt App (Frontend)
|
||||
|
||||
```bash
|
||||
cd app
|
||||
bun install
|
||||
bun run dev
|
||||
```
|
||||
|
||||
**App running:** `http://localhost:3000`
|
||||
|
||||
### 5. Open & Test
|
||||
|
||||
1. Visit `http://localhost:3000`
|
||||
2. Click "Add Manually" to create your first inventory item
|
||||
3. Access Supabase Studio at `http://localhost:54323` to view database
|
||||
|
||||
---
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
pantry/
|
||||
├── app/ # Nuxt 4 frontend
|
||||
│ ├── components/ # Vue components
|
||||
│ │ └── inventory/ # Inventory CRUD UI
|
||||
│ ├── composables/ # Supabase client, data hooks
|
||||
│ ├── pages/ # Routes (index, scan, settings)
|
||||
│ └── types/ # TypeScript definitions
|
||||
├── supabase/
|
||||
│ └── migrations/ # SQL schema & seed data
|
||||
├── docker/
|
||||
│ └── kong.yml # API gateway config
|
||||
├── docker-compose.yml # Supabase services
|
||||
└── .env # Environment variables
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Common Tasks
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# All services
|
||||
docker-compose logs -f
|
||||
|
||||
# Specific service
|
||||
docker-compose logs -f db
|
||||
docker-compose logs -f auth
|
||||
```
|
||||
|
||||
### Reset Database
|
||||
|
||||
```bash
|
||||
# Stop services
|
||||
docker-compose down -v
|
||||
|
||||
# Restart (migrations auto-apply)
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Access Database
|
||||
|
||||
```bash
|
||||
# psql
|
||||
docker-compose exec db psql -U postgres -d postgres
|
||||
|
||||
# Supabase Studio (GUI)
|
||||
# http://localhost:54323
|
||||
```
|
||||
|
||||
### Run Migrations Manually
|
||||
|
||||
```bash
|
||||
# If you add new migrations after initial setup
|
||||
docker-compose exec db psql -U postgres -d postgres -f /docker-entrypoint-initdb.d/003_helper_functions.sql
|
||||
```
|
||||
|
||||
### Create Test User
|
||||
|
||||
```bash
|
||||
# Via Supabase Studio: http://localhost:54323
|
||||
# → Authentication → Add User
|
||||
# Email: test@example.com
|
||||
# Password: password123
|
||||
|
||||
# Or via curl:
|
||||
curl http://localhost:54321/auth/v1/signup \
|
||||
-H "apikey: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email":"test@example.com","password":"password123"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Testing Features
|
||||
|
||||
### 1. Inventory Management
|
||||
- Add items manually via form
|
||||
- Edit quantities with +/- buttons
|
||||
- Delete items
|
||||
- View expiry warnings
|
||||
|
||||
### 2. Tags & Organization
|
||||
- Pre-seeded tags: Fridge, Freezer, Pantry, Dairy, Vegan, etc.
|
||||
- Multi-select tags when adding items
|
||||
- Color-coded badges
|
||||
|
||||
### 3. Units
|
||||
- 30 pre-seeded units (g, kg, L, cups, pieces, etc.)
|
||||
- Automatic conversion support
|
||||
|
||||
### 4. Barcode Scanning (Week 3 - In Progress)
|
||||
- Camera access (requires HTTPS in production)
|
||||
- Manual barcode entry fallback
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Port Conflicts
|
||||
|
||||
If ports 5432, 54321, or 3000 are in use:
|
||||
|
||||
```bash
|
||||
# Check what's using the port
|
||||
sudo lsof -i :5432
|
||||
|
||||
# Option 1: Stop conflicting service
|
||||
# Option 2: Change port in docker-compose.yml
|
||||
```
|
||||
|
||||
### Database Connection Refused
|
||||
|
||||
```bash
|
||||
# Wait for PostgreSQL to fully start
|
||||
docker-compose logs db | grep "ready to accept connections"
|
||||
|
||||
# If stuck, restart
|
||||
docker-compose restart db
|
||||
```
|
||||
|
||||
### Migrations Not Applied
|
||||
|
||||
```bash
|
||||
# Verify migrations directory is mounted
|
||||
docker-compose exec db ls -la /docker-entrypoint-initdb.d
|
||||
|
||||
# Manually apply
|
||||
docker-compose exec db bash
|
||||
cd /docker-entrypoint-initdb.d
|
||||
for f in *.sql; do psql -U postgres -d postgres -f "$f"; done
|
||||
```
|
||||
|
||||
### Frontend: Module Not Found
|
||||
|
||||
```bash
|
||||
cd app
|
||||
rm -rf node_modules bun.lock .nuxt
|
||||
bun install
|
||||
bun run dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Database Schema
|
||||
|
||||
### Tables
|
||||
|
||||
| Table | Purpose | Rows (Est.) |
|
||||
|-------|---------|-------------|
|
||||
| `inventory_items` | Current inventory | 100-500 |
|
||||
| `products` | Barcode cache (Open Food Facts) | 500-2000 |
|
||||
| `tags` | Organization labels | 50 (33 pre-seeded) |
|
||||
| `units` | Measurement units | 50 (30 pre-seeded) |
|
||||
| `item_tags` | Many-to-many item ↔ tag | 200-1000 |
|
||||
|
||||
### Pre-Seeded Data
|
||||
|
||||
**Units (30):**
|
||||
- Weight: g, kg, mg, lb, oz
|
||||
- Volume: mL, L, cup, tbsp, tsp, gal, qt, pt
|
||||
- Count: piece, dozen, package, bottle, can, jar, box, bag
|
||||
|
||||
**Tags (33):**
|
||||
- Position: Fridge, Freezer, Pantry, Cabinet
|
||||
- Type: Dairy, Meat, Vegetables, Fruits, Snacks
|
||||
- Dietary: Vegan, Gluten-Free, Organic, Kosher, Halal
|
||||
- Custom: Low Stock, To Buy, Meal Prep, Leftovers
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Authentication
|
||||
|
||||
**Default Setup (Development):**
|
||||
- Auto-confirm emails (no SMTP needed)
|
||||
- Anyone can sign up
|
||||
- JWT tokens valid for 1 hour
|
||||
|
||||
**Create Admin User:**
|
||||
|
||||
```sql
|
||||
-- Via psql
|
||||
docker-compose exec db psql -U postgres -d postgres
|
||||
|
||||
INSERT INTO auth.users (id, email, encrypted_password, email_confirmed_at)
|
||||
VALUES (
|
||||
gen_random_uuid(),
|
||||
'admin@pantry.local',
|
||||
crypt('admin123', gen_salt('bf')),
|
||||
NOW()
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Environment Variables
|
||||
|
||||
**.env** (root)
|
||||
```bash
|
||||
POSTGRES_PASSWORD=postgres
|
||||
JWT_SECRET=your-secret-here
|
||||
ANON_KEY=<supabase-anon-key>
|
||||
SERVICE_ROLE_KEY=<supabase-service-role-key>
|
||||
```
|
||||
|
||||
**app/.env** (Nuxt)
|
||||
```bash
|
||||
NUXT_PUBLIC_SUPABASE_URL=http://localhost:54321
|
||||
NUXT_PUBLIC_SUPABASE_ANON_KEY=<same-as-above>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 Development Workflow
|
||||
|
||||
1. **Make changes** to Nuxt app → Hot reload at `localhost:3000`
|
||||
2. **Database changes** → Create new migration in `supabase/migrations/`
|
||||
3. **Test** → Add items, scan barcodes, check database
|
||||
4. **Commit** → Feature branch → PR to `develop`
|
||||
|
||||
---
|
||||
|
||||
## 🚢 Production Deployment (Coming Soon)
|
||||
|
||||
See `docs/DEPLOYMENT.md` for:
|
||||
- Coolify setup
|
||||
- Environment configuration
|
||||
- SSL/HTTPS setup
|
||||
- Backups
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
- [Architecture](docs/ARCHITECTURE.md)
|
||||
- [Database Schema](docs/DATABASE.md)
|
||||
- [API Reference](docs/API.md)
|
||||
- [Development Guide](docs/DEVELOPMENT.md)
|
||||
|
||||
---
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
This is a personal project, but issues and PRs welcome!
|
||||
|
||||
1. Fork the repo
|
||||
2. Create feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit changes (`git commit -m 'Add amazing feature'`)
|
||||
4. Push to branch (`git push origin feature/amazing-feature`)
|
||||
5. Open Pull Request
|
||||
|
||||
---
|
||||
|
||||
## 📝 License
|
||||
|
||||
MIT License - See LICENSE file
|
||||
|
||||
---
|
||||
|
||||
## 🙋 Support
|
||||
|
||||
- Issues: https://gitea.jeanlucmakiola.de/pantry-app/pantry/issues
|
||||
- Docs: https://gitea.jeanlucmakiola.de/pantry-app/pantry/wiki
|
||||
|
||||
---
|
||||
|
||||
**Version:** 0.1.0-alpha (MVP in progress)
|
||||
**Status:** Week 2 complete, Week 3 in progress (14/34 issues done)
|
||||
@@ -8,6 +8,7 @@
|
||||
"@nuxt/fonts": "^0.13.0",
|
||||
"@nuxt/ui": "^4.4.0",
|
||||
"@supabase/supabase-js": "^2.95.3",
|
||||
"html5-qrcode": "^2.3.8",
|
||||
"nuxt": "^4.3.1",
|
||||
"vue": "^3.5.28",
|
||||
"vue-router": "^4.6.4",
|
||||
@@ -1076,6 +1077,8 @@
|
||||
|
||||
"hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
|
||||
|
||||
"html5-qrcode": ["html5-qrcode@2.3.8", "", {}, "sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ=="],
|
||||
|
||||
"http-assert": ["http-assert@1.5.0", "", { "dependencies": { "deep-equal": "~1.0.1", "http-errors": "~1.8.0" } }, "sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w=="],
|
||||
|
||||
"http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
|
||||
|
||||
161
app/components/scan/BarcodeScanner.vue
Normal file
161
app/components/scan/BarcodeScanner.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div class="relative">
|
||||
<!-- Scanner Container -->
|
||||
<div
|
||||
:id="scannerId"
|
||||
ref="scannerRef"
|
||||
class="w-full rounded-lg overflow-hidden bg-black"
|
||||
:class="{ 'aspect-video': !isScanning, 'min-h-[300px]': isScanning }"
|
||||
/>
|
||||
|
||||
<!-- Overlay when not scanning -->
|
||||
<div
|
||||
v-if="!isScanning && !error"
|
||||
class="absolute inset-0 flex items-center justify-center bg-gray-900 rounded-lg"
|
||||
>
|
||||
<div class="text-center">
|
||||
<UIcon name="i-heroicons-camera" class="w-16 h-16 text-gray-400 mb-4" />
|
||||
<UButton
|
||||
color="primary"
|
||||
size="lg"
|
||||
icon="i-heroicons-qr-code"
|
||||
@click="startScanning"
|
||||
>
|
||||
Start Camera
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error State -->
|
||||
<div
|
||||
v-if="error"
|
||||
class="absolute inset-0 flex items-center justify-center bg-gray-900 rounded-lg"
|
||||
>
|
||||
<div class="text-center px-4">
|
||||
<UIcon name="i-heroicons-exclamation-triangle" class="w-12 h-12 text-red-400 mb-4" />
|
||||
<p class="text-white mb-4">{{ error }}</p>
|
||||
<div class="flex gap-2 justify-center">
|
||||
<UButton @click="startScanning" color="primary">Try Again</UButton>
|
||||
<UButton @click="$emit('manual-entry')" color="gray">Enter Manually</UButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Manual Barcode Entry -->
|
||||
<div class="mt-4">
|
||||
<UFormGroup label="Or enter barcode manually">
|
||||
<div class="flex gap-2">
|
||||
<UInput
|
||||
v-model="manualBarcode"
|
||||
placeholder="e.g. 8000500310427"
|
||||
size="lg"
|
||||
class="flex-1"
|
||||
@keyup.enter="submitManualBarcode"
|
||||
/>
|
||||
<UButton
|
||||
color="primary"
|
||||
size="lg"
|
||||
:disabled="!manualBarcode.trim()"
|
||||
@click="submitManualBarcode"
|
||||
>
|
||||
Lookup
|
||||
</UButton>
|
||||
</div>
|
||||
</UFormGroup>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Html5Qrcode, Html5QrcodeSupportedFormats } from 'html5-qrcode'
|
||||
|
||||
const emit = defineEmits<{
|
||||
'barcode-detected': [barcode: string]
|
||||
'manual-entry': []
|
||||
}>()
|
||||
|
||||
const scannerId = 'barcode-scanner'
|
||||
const scannerRef = ref<HTMLElement | null>(null)
|
||||
const isScanning = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
const manualBarcode = ref('')
|
||||
|
||||
let html5QrCode: Html5Qrcode | null = null
|
||||
|
||||
const startScanning = async () => {
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
if (!html5QrCode) {
|
||||
html5QrCode = new Html5Qrcode(scannerId, {
|
||||
formatsToSupport: [
|
||||
Html5QrcodeSupportedFormats.EAN_13,
|
||||
Html5QrcodeSupportedFormats.EAN_8,
|
||||
Html5QrcodeSupportedFormats.UPC_A,
|
||||
Html5QrcodeSupportedFormats.UPC_E,
|
||||
Html5QrcodeSupportedFormats.CODE_128,
|
||||
Html5QrcodeSupportedFormats.CODE_39,
|
||||
Html5QrcodeSupportedFormats.QR_CODE
|
||||
],
|
||||
verbose: false
|
||||
})
|
||||
}
|
||||
|
||||
await html5QrCode.start(
|
||||
{ facingMode: 'environment' },
|
||||
{
|
||||
fps: 10,
|
||||
qrbox: { width: 250, height: 150 },
|
||||
aspectRatio: 1.777
|
||||
},
|
||||
onScanSuccess,
|
||||
onScanFailure
|
||||
)
|
||||
|
||||
isScanning.value = true
|
||||
} catch (err: any) {
|
||||
console.error('Scanner error:', err)
|
||||
|
||||
if (err.toString().includes('NotAllowedError')) {
|
||||
error.value = 'Camera permission denied. Please allow camera access and try again.'
|
||||
} else if (err.toString().includes('NotFoundError')) {
|
||||
error.value = 'No camera found. Please use a device with a camera or enter the barcode manually.'
|
||||
} else {
|
||||
error.value = 'Could not start camera. Try entering the barcode manually.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const stopScanning = async () => {
|
||||
if (html5QrCode && isScanning.value) {
|
||||
try {
|
||||
await html5QrCode.stop()
|
||||
} catch (err) {
|
||||
console.error('Error stopping scanner:', err)
|
||||
}
|
||||
isScanning.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const onScanSuccess = (decodedText: string) => {
|
||||
// Stop scanning after successful read
|
||||
stopScanning()
|
||||
emit('barcode-detected', decodedText)
|
||||
}
|
||||
|
||||
const onScanFailure = (_errorMessage: string) => {
|
||||
// Ignore - this fires continuously when no barcode is detected
|
||||
}
|
||||
|
||||
const submitManualBarcode = () => {
|
||||
if (manualBarcode.value.trim()) {
|
||||
emit('barcode-detected', manualBarcode.value.trim())
|
||||
manualBarcode.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup on unmount
|
||||
onUnmounted(() => {
|
||||
stopScanning()
|
||||
})
|
||||
</script>
|
||||
@@ -13,6 +13,7 @@
|
||||
"@nuxt/fonts": "^0.13.0",
|
||||
"@nuxt/ui": "^4.4.0",
|
||||
"@supabase/supabase-js": "^2.95.3",
|
||||
"html5-qrcode": "^2.3.8",
|
||||
"nuxt": "^4.3.1",
|
||||
"vue": "^3.5.28",
|
||||
"vue-router": "^4.6.4"
|
||||
|
||||
127
docker-compose.yml
Normal file
127
docker-compose.yml
Normal file
@@ -0,0 +1,127 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# PostgreSQL Database
|
||||
db:
|
||||
image: supabase/postgres:15.1.0.147
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||
POSTGRES_DB: postgres
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
- ./supabase/migrations:/docker-entrypoint-initdb.d:ro
|
||||
|
||||
# Supabase Studio (Admin UI)
|
||||
studio:
|
||||
image: supabase/studio:20231123-64a766a
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "54323:3000"
|
||||
environment:
|
||||
SUPABASE_URL: http://kong:8000
|
||||
SUPABASE_PUBLIC_URL: http://localhost:54321
|
||||
SUPABASE_ANON_KEY: ${ANON_KEY}
|
||||
SUPABASE_SERVICE_KEY: ${SERVICE_ROLE_KEY}
|
||||
|
||||
# Kong API Gateway
|
||||
kong:
|
||||
image: kong:2.8.1
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "54321:8000"
|
||||
- "54320:8443"
|
||||
environment:
|
||||
KONG_DATABASE: "off"
|
||||
KONG_DECLARATIVE_CONFIG: /var/lib/kong/kong.yml
|
||||
KONG_DNS_ORDER: LAST,A,CNAME
|
||||
KONG_PLUGINS: request-transformer,cors,key-auth,acl
|
||||
volumes:
|
||||
- ./docker/kong.yml:/var/lib/kong/kong.yml:ro
|
||||
|
||||
# GoTrue (Auth)
|
||||
auth:
|
||||
image: supabase/gotrue:v2.99.0
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
environment:
|
||||
GOTRUE_API_HOST: 0.0.0.0
|
||||
GOTRUE_API_PORT: 9999
|
||||
API_EXTERNAL_URL: http://localhost:54321
|
||||
GOTRUE_DB_DRIVER: postgres
|
||||
GOTRUE_DB_DATABASE_URL: postgres://supabase_auth_admin:${POSTGRES_PASSWORD:-postgres}@db:5432/postgres
|
||||
GOTRUE_SITE_URL: http://localhost:3000
|
||||
GOTRUE_URI_ALLOW_LIST: "*"
|
||||
GOTRUE_DISABLE_SIGNUP: false
|
||||
GOTRUE_JWT_ADMIN_ROLES: service_role
|
||||
GOTRUE_JWT_AUD: authenticated
|
||||
GOTRUE_JWT_DEFAULT_GROUP_NAME: authenticated
|
||||
GOTRUE_JWT_EXP: 3600
|
||||
GOTRUE_JWT_SECRET: ${JWT_SECRET}
|
||||
GOTRUE_EXTERNAL_EMAIL_ENABLED: true
|
||||
GOTRUE_MAILER_AUTOCONFIRM: true
|
||||
|
||||
# PostgREST (Auto API)
|
||||
rest:
|
||||
image: postgrest/postgrest:v11.2.0
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
environment:
|
||||
PGRST_DB_URI: postgres://authenticator:${POSTGRES_PASSWORD:-postgres}@db:5432/postgres
|
||||
PGRST_DB_SCHEMAS: public,storage
|
||||
PGRST_DB_ANON_ROLE: anon
|
||||
PGRST_JWT_SECRET: ${JWT_SECRET}
|
||||
PGRST_DB_USE_LEGACY_GUCS: "false"
|
||||
|
||||
# Realtime
|
||||
realtime:
|
||||
image: supabase/realtime:v2.25.35
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
environment:
|
||||
PORT: 4000
|
||||
DB_HOST: db
|
||||
DB_PORT: 5432
|
||||
DB_USER: supabase_admin
|
||||
DB_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||
DB_NAME: postgres
|
||||
DB_AFTER_CONNECT_QUERY: 'SET search_path TO _realtime'
|
||||
DB_ENC_KEY: supabaserealtime
|
||||
API_JWT_SECRET: ${JWT_SECRET}
|
||||
FLY_ALLOC_ID: fly123
|
||||
FLY_APP_NAME: realtime
|
||||
SECRET_KEY_BASE: ${JWT_SECRET}
|
||||
ERL_AFLAGS: -proto_dist inet_tcp
|
||||
ENABLE_TAILSCALE: "false"
|
||||
DNS_NODES: "''"
|
||||
|
||||
# Storage (S3-compatible)
|
||||
storage:
|
||||
image: supabase/storage-api:v0.40.4
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
- rest
|
||||
environment:
|
||||
ANON_KEY: ${ANON_KEY}
|
||||
SERVICE_KEY: ${SERVICE_ROLE_KEY}
|
||||
POSTGREST_URL: http://rest:3000
|
||||
PGRST_JWT_SECRET: ${JWT_SECRET}
|
||||
DATABASE_URL: postgres://supabase_storage_admin:${POSTGRES_PASSWORD:-postgres}@db:5432/postgres
|
||||
FILE_SIZE_LIMIT: 52428800
|
||||
STORAGE_BACKEND: file
|
||||
FILE_STORAGE_BACKEND_PATH: /var/lib/storage
|
||||
TENANT_ID: stub
|
||||
REGION: stub
|
||||
GLOBAL_S3_BUCKET: stub
|
||||
volumes:
|
||||
- storage-data:/var/lib/storage
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
storage-data:
|
||||
85
docker/kong.yml
Normal file
85
docker/kong.yml
Normal file
@@ -0,0 +1,85 @@
|
||||
_format_version: "2.1"
|
||||
|
||||
_transform: true
|
||||
|
||||
services:
|
||||
- name: auth
|
||||
url: http://auth:9999
|
||||
routes:
|
||||
- name: auth-v1
|
||||
strip_path: true
|
||||
paths:
|
||||
- /auth/v1
|
||||
plugins:
|
||||
- name: cors
|
||||
- name: key-auth
|
||||
config:
|
||||
hide_credentials: true
|
||||
|
||||
- name: rest
|
||||
url: http://rest:3000
|
||||
routes:
|
||||
- name: rest-v1
|
||||
strip_path: true
|
||||
paths:
|
||||
- /rest/v1
|
||||
plugins:
|
||||
- name: cors
|
||||
- name: key-auth
|
||||
config:
|
||||
hide_credentials: true
|
||||
|
||||
- name: realtime
|
||||
url: http://realtime:4000/socket
|
||||
routes:
|
||||
- name: realtime-v1
|
||||
strip_path: true
|
||||
paths:
|
||||
- /realtime/v1
|
||||
plugins:
|
||||
- name: cors
|
||||
- name: key-auth
|
||||
config:
|
||||
hide_credentials: true
|
||||
|
||||
- name: storage
|
||||
url: http://storage:5000
|
||||
routes:
|
||||
- name: storage-v1
|
||||
strip_path: true
|
||||
paths:
|
||||
- /storage/v1
|
||||
plugins:
|
||||
- name: cors
|
||||
|
||||
consumers:
|
||||
- username: anon
|
||||
keyauth_credentials:
|
||||
- key: ${ANON_KEY}
|
||||
- username: service_role
|
||||
keyauth_credentials:
|
||||
- key: ${SERVICE_ROLE_KEY}
|
||||
|
||||
plugins:
|
||||
- name: cors
|
||||
config:
|
||||
origins:
|
||||
- "*"
|
||||
methods:
|
||||
- GET
|
||||
- POST
|
||||
- PUT
|
||||
- PATCH
|
||||
- DELETE
|
||||
- OPTIONS
|
||||
headers:
|
||||
- Accept
|
||||
- Accept-Encoding
|
||||
- Authorization
|
||||
- Content-Type
|
||||
- Origin
|
||||
- X-Client-Info
|
||||
exposed_headers:
|
||||
- X-Total-Count
|
||||
credentials: true
|
||||
max_age: 3600
|
||||
Reference in New Issue
Block a user