Mobile-first Web-App fuer persoenliches Health-, Ernaehrungs-, Aktivitaets- und Einkaufs-Tracking im Home-Lab-Betrieb. Stack: pnpm Monorepo - Next.js 16 + React 19 + Tailwind (apps/admin) - Hono + tRPC + Better Auth mit 2FA und Passkeys (packages/api) - PostgreSQL + Drizzle ORM (packages/db) - Docker fuer Postgres und pgAdmin. Module: - Auth mit Login, 2FA (TOTP + Backup-Codes), Passkeys und Admin-Recovery - Tagesansicht mit Essen, Trinken, Gewicht, Aktivitaeten und Coach-Hinweisen - Lebensmittelkatalog mit Naehrwerten, Portionen, OCR/Barcode/Open Food Facts - Rezepte mit Live-Naehrwertberechnung und Community-Vorschlaegen - Essensplanung und Wochenbudget mit Sportbonus - Einkaufslisten mit Maerkten und Laufweg-Sortierung - Hellfireclub mit Aktivitaetspunkten und gemeinsamer Aktivitaetsplanung - Wearables-Vorbereitung (Fitbit / Google Fit / Health Connect) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
41 lines
2.7 KiB
SQL
41 lines
2.7 KiB
SQL
CREATE TYPE "public"."newsletter_subscription_status" AS ENUM('pending_double_opt_in', 'subscribed', 'unsubscribed');--> statement-breakpoint
|
|
CREATE TABLE "tenant_newsletter_lists" (
|
|
"id" text PRIMARY KEY NOT NULL,
|
|
"tenantId" text NOT NULL,
|
|
"key" text NOT NULL,
|
|
"name" text NOT NULL,
|
|
"description" text,
|
|
"isActive" boolean DEFAULT true NOT NULL,
|
|
"createdAt" timestamp DEFAULT now() NOT NULL,
|
|
"updatedAt" timestamp DEFAULT now() NOT NULL
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE "tenant_newsletter_subscriptions" (
|
|
"id" text PRIMARY KEY NOT NULL,
|
|
"tenantId" text NOT NULL,
|
|
"userId" text NOT NULL,
|
|
"newsletterListId" text NOT NULL,
|
|
"status" "newsletter_subscription_status" DEFAULT 'pending_double_opt_in' NOT NULL,
|
|
"doubleOptInRequestedAt" timestamp,
|
|
"doubleOptInConfirmedAt" timestamp,
|
|
"unsubscribedAt" timestamp,
|
|
"createdAt" timestamp DEFAULT now() NOT NULL,
|
|
"updatedAt" timestamp DEFAULT now() NOT NULL
|
|
);
|
|
--> statement-breakpoint
|
|
ALTER TABLE "tenant_newsletter_lists" ADD CONSTRAINT "tenant_newsletter_lists_tenantId_tenants_id_fk" FOREIGN KEY ("tenantId") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "tenant_newsletter_subscriptions" ADD CONSTRAINT "tenant_newsletter_subscriptions_tenantId_tenants_id_fk" FOREIGN KEY ("tenantId") REFERENCES "public"."tenants"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "tenant_newsletter_subscriptions" ADD CONSTRAINT "tenant_newsletter_subscriptions_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "tenant_newsletter_subscriptions" ADD CONSTRAINT "tenant_newsletter_subscriptions_newsletterListId_tenant_newsletter_lists_id_fk" FOREIGN KEY ("newsletterListId") REFERENCES "public"."tenant_newsletter_lists"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
|
CREATE UNIQUE INDEX "tenant_newsletter_lists_tenant_key_unique" ON "tenant_newsletter_lists" USING btree ("tenantId","key");--> statement-breakpoint
|
|
CREATE UNIQUE INDEX "tenant_newsletter_subscriptions_tenant_user_list_unique" ON "tenant_newsletter_subscriptions" USING btree ("tenantId","userId","newsletterListId");
|
|
--> statement-breakpoint
|
|
INSERT INTO "tenant_newsletter_lists" ("id", "tenantId", "key", "name")
|
|
SELECT "id" || ':newsletter-ortsgruppe', "id", 'newsletter-ortsgruppe', 'Newsletter Ortsgruppe'
|
|
FROM "tenants"
|
|
ON CONFLICT ("tenantId", "key") DO NOTHING;
|
|
--> statement-breakpoint
|
|
INSERT INTO "tenant_newsletter_lists" ("id", "tenantId", "key", "name")
|
|
SELECT "id" || ':newsletter-aktive-familie', "id", 'newsletter-aktive-familie', 'Newsletter Aktive Familie'
|
|
FROM "tenants"
|
|
ON CONFLICT ("tenantId", "key") DO NOTHING;
|