-- CreateSchema CREATE SCHEMA IF NOT EXISTS "public"; -- CreateEnum CREATE TYPE "measurement_type" AS ENUM ('WEIGHT', 'BLOOD_PRESSURE_SYS', 'BLOOD_PRESSURE_DIA', 'PULSE', 'BODY_FAT', 'SLEEP_DURATION', 'ACTIVITY_STEPS'); -- CreateEnum CREATE TYPE "measurement_source" AS ENUM ('MANUAL', 'WITHINGS', 'IMPORT'); -- CreateEnum CREATE TYPE "intake_source" AS ENUM ('WEB', 'API', 'REMINDER'); -- CreateTable CREATE TABLE "users" ( "id" TEXT NOT NULL, "username" TEXT NOT NULL, "email" TEXT, "password_hash" TEXT, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, "height_cm" DOUBLE PRECISION, "timezone" TEXT NOT NULL DEFAULT 'Europe/Berlin', "bp_sys_target_low" INTEGER, "bp_sys_target_high" INTEGER, "bp_dia_target_low" INTEGER, "bp_dia_target_high" INTEGER, "openai_key_encrypted" TEXT, "insights_privacy_mode" TEXT NOT NULL DEFAULT 'aggregated', "insights_cached_at" TIMESTAMP(3), "insights_cached_text" TEXT, CONSTRAINT "users_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "passkeys" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "name" TEXT NOT NULL DEFAULT 'Passkey', "credential_id" TEXT NOT NULL, "credential_public_key" BYTEA NOT NULL, "counter" BIGINT NOT NULL DEFAULT 0, "credential_device_type" TEXT NOT NULL, "credential_backed_up" BOOLEAN NOT NULL DEFAULT false, "transports" TEXT[], "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "passkeys_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "sessions" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "expires_at" TIMESTAMP(3) NOT NULL, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "ip_address" TEXT, "user_agent" TEXT, CONSTRAINT "sessions_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "auth_challenges" ( "id" TEXT NOT NULL, "user_id" TEXT, "challenge" TEXT NOT NULL, "type" TEXT NOT NULL, "expires_at" TIMESTAMP(3) NOT NULL, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "auth_challenges_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "measurements" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "type" "measurement_type" NOT NULL, "value" DOUBLE PRECISION NOT NULL, "unit" TEXT NOT NULL, "source" "measurement_source" NOT NULL DEFAULT 'MANUAL', "measured_at" TIMESTAMP(3) NOT NULL, "notes" TEXT, "external_id" TEXT, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "measurements_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "medications" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "name" TEXT NOT NULL, "dose" TEXT NOT NULL, "active" BOOLEAN NOT NULL DEFAULT true, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "medications_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "medication_schedules" ( "id" TEXT NOT NULL, "medication_id" TEXT NOT NULL, "windowStart" TEXT NOT NULL, "windowEnd" TEXT NOT NULL, "label" TEXT, CONSTRAINT "medication_schedules_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "medication_intake_events" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "medication_id" TEXT NOT NULL, "scheduled_for" TIMESTAMP(3) NOT NULL, "taken_at" TIMESTAMP(3), "skipped" BOOLEAN NOT NULL DEFAULT false, "source" "intake_source" NOT NULL DEFAULT 'WEB', "idempotency_key" TEXT, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "medication_intake_events_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "api_tokens" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "name" TEXT NOT NULL, "token_hash" TEXT NOT NULL, "permissions" TEXT[] DEFAULT ARRAY['medication:ingest']::TEXT[], "last_used_at" TIMESTAMP(3), "expires_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "revoked" BOOLEAN NOT NULL DEFAULT false, CONSTRAINT "api_tokens_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "withings_connections" ( "id" TEXT NOT NULL, "user_id" TEXT NOT NULL, "withings_user_id" TEXT NOT NULL, "access_token" TEXT NOT NULL, "refresh_token" TEXT NOT NULL, "token_expires_at" TIMESTAMP(3) NOT NULL, "last_synced_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "withings_connections_pkey" PRIMARY KEY ("id") ); -- CreateTable CREATE TABLE "audit_logs" ( "id" TEXT NOT NULL, "user_id" TEXT, "action" TEXT NOT NULL, "details" TEXT, "ip_address" TEXT, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "audit_logs_pkey" PRIMARY KEY ("id") ); -- CreateIndex CREATE UNIQUE INDEX "users_username_key" ON "users"("username"); -- CreateIndex CREATE UNIQUE INDEX "users_email_key" ON "users"("email"); -- CreateIndex CREATE UNIQUE INDEX "passkeys_credential_id_key" ON "passkeys"("credential_id"); -- CreateIndex CREATE INDEX "sessions_user_id_idx" ON "sessions"("user_id"); -- CreateIndex CREATE INDEX "auth_challenges_user_id_idx" ON "auth_challenges"("user_id"); -- CreateIndex CREATE INDEX "measurements_user_id_type_measured_at_idx" ON "measurements"("user_id", "type", "measured_at"); -- CreateIndex CREATE INDEX "measurements_external_id_idx" ON "measurements"("external_id"); -- CreateIndex CREATE UNIQUE INDEX "measurements_user_id_type_measured_at_source_key" ON "measurements"("user_id", "type", "measured_at", "source"); -- CreateIndex CREATE INDEX "medications_user_id_idx" ON "medications"("user_id"); -- CreateIndex CREATE UNIQUE INDEX "medication_intake_events_idempotency_key_key" ON "medication_intake_events"("idempotency_key"); -- CreateIndex CREATE INDEX "medication_intake_events_user_id_medication_id_scheduled_fo_idx" ON "medication_intake_events"("user_id", "medication_id", "scheduled_for"); -- CreateIndex CREATE UNIQUE INDEX "api_tokens_token_hash_key" ON "api_tokens"("token_hash"); -- CreateIndex CREATE INDEX "api_tokens_user_id_idx" ON "api_tokens"("user_id"); -- CreateIndex CREATE UNIQUE INDEX "withings_connections_user_id_key" ON "withings_connections"("user_id"); -- CreateIndex CREATE INDEX "audit_logs_user_id_created_at_idx" ON "audit_logs"("user_id", "created_at"); -- CreateIndex CREATE INDEX "audit_logs_action_created_at_idx" ON "audit_logs"("action", "created_at"); -- AddForeignKey ALTER TABLE "passkeys" ADD CONSTRAINT "passkeys_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "auth_challenges" ADD CONSTRAINT "auth_challenges_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "measurements" ADD CONSTRAINT "measurements_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "medications" ADD CONSTRAINT "medications_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "medication_schedules" ADD CONSTRAINT "medication_schedules_medication_id_fkey" FOREIGN KEY ("medication_id") REFERENCES "medications"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "medication_intake_events" ADD CONSTRAINT "medication_intake_events_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "medication_intake_events" ADD CONSTRAINT "medication_intake_events_medication_id_fkey" FOREIGN KEY ("medication_id") REFERENCES "medications"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "api_tokens" ADD CONSTRAINT "api_tokens_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "withings_connections" ADD CONSTRAINT "withings_connections_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE "audit_logs" ADD CONSTRAINT "audit_logs_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;