-- Moon Base v0.1 — initial schema -- Creates auth, audit log, and the garden plant registry. -- Enums CREATE TYPE "UserRole" AS ENUM ('ADMIN', 'MEMBER'); CREATE TYPE "PlantCategory" AS ENUM ( 'CANOPY_TREE', 'UNDERSTORY_TREE', 'LARGE_SHRUB', 'SHRUB', 'HERB', 'GROUNDCOVER', 'VINE', 'ANNUAL', 'PERENNIAL', 'BULB', 'MUSHROOM', 'OTHER' ); CREATE TYPE "PlantLogType" AS ENUM ( 'OBSERVATION', 'CARE', 'HARVEST', 'TREATMENT', 'TRANSPLANT', 'DIED' ); -- User CREATE TABLE "User" ( "id" TEXT NOT NULL, "email" TEXT NOT NULL, "username" TEXT, "name" TEXT NOT NULL, "passwordHash" TEXT NOT NULL, "role" "UserRole" NOT NULL DEFAULT 'MEMBER', "active" BOOLEAN NOT NULL DEFAULT true, "mustChangePassword" BOOLEAN NOT NULL DEFAULT false, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, CONSTRAINT "User_pkey" PRIMARY KEY ("id") ); CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); CREATE UNIQUE INDEX "User_username_key" ON "User"("username"); -- AuditEvent CREATE TABLE "AuditEvent" ( "id" TEXT NOT NULL, "action" TEXT NOT NULL, "entityId" TEXT, "actorId" TEXT, "payload" JSONB, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "AuditEvent_pkey" PRIMARY KEY ("id") ); CREATE INDEX "AuditEvent_entityId_idx" ON "AuditEvent"("entityId"); CREATE INDEX "AuditEvent_createdAt_idx" ON "AuditEvent"("createdAt"); -- Plant CREATE TABLE "Plant" ( "id" TEXT NOT NULL, "commonName" TEXT NOT NULL, "species" TEXT, "variety" TEXT, "category" "PlantCategory" NOT NULL, "zone" TEXT, "plantedAt" TIMESTAMP(3), "source" TEXT, "notes" TEXT, "active" BOOLEAN NOT NULL DEFAULT true, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updatedAt" TIMESTAMP(3) NOT NULL, CONSTRAINT "Plant_pkey" PRIMARY KEY ("id") ); CREATE INDEX "Plant_category_idx" ON "Plant"("category"); CREATE INDEX "Plant_zone_idx" ON "Plant"("zone"); CREATE INDEX "Plant_active_idx" ON "Plant"("active"); -- PlantLog CREATE TABLE "PlantLog" ( "id" TEXT NOT NULL, "plantId" TEXT NOT NULL, "type" "PlantLogType" NOT NULL, "date" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "notes" TEXT, "quantity" TEXT, "actorId" TEXT, "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "PlantLog_pkey" PRIMARY KEY ("id"), CONSTRAINT "PlantLog_plantId_fkey" FOREIGN KEY ("plantId") REFERENCES "Plant"("id") ON DELETE RESTRICT ON UPDATE CASCADE ); CREATE INDEX "PlantLog_plantId_idx" ON "PlantLog"("plantId"); CREATE INDEX "PlantLog_date_idx" ON "PlantLog"("date"); -- Provision admin accounts (bonna + tony) -- Passwords are bcrypt hashes of temporary values — change on first login. -- bonna: moonbase! | tony: moonbase! INSERT INTO "User" ("id", "email", "username", "name", "passwordHash", "role", "active", "mustChangePassword", "createdAt", "updatedAt") VALUES ('cluser0000000bonna', 'bonna@moonbase.local', 'bonna', 'Bonna Moon', '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'ADMIN', true, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), ('cluser0000000tony0', 'tony@moonbase.local', 'tony', 'Tony Moon', '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'ADMIN', true, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) ON CONFLICT ("username") DO UPDATE SET "updatedAt" = CURRENT_TIMESTAMP;