diff --git a/api/prisma/migrations/66_key_level_translation_content/migration.sql b/api/prisma/migrations/66_key_level_translation_content/migration.sql new file mode 100644 index 0000000000..a2b3898422 --- /dev/null +++ b/api/prisma/migrations/66_key_level_translation_content/migration.sql @@ -0,0 +1,52 @@ +-- CreateEnum +CREATE TYPE "site_enum" AS ENUM ('public', 'partners'); + +-- CreateEnum +CREATE TYPE "translation_origin" AS ENUM ('machine', 'human'); + +-- CreateTable +CREATE TABLE "jurisdiction_content" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v4(), + "created_at" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(6) NOT NULL, + "jurisdiction_id" UUID NOT NULL, + "language" "languages_enum" NOT NULL, + "footer" JSONB, + "faq" JSONB, + "resources" JSONB, + "disclaimers" JSONB, + "contact" JSONB, + + CONSTRAINT "jurisdiction_content_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "translation_strings" ( + "id" UUID NOT NULL DEFAULT uuid_generate_v4(), + "created_at" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(6) NOT NULL, + "jurisdiction_id" UUID, + "language" "languages_enum" NOT NULL, + "site" "site_enum", + "key" TEXT NOT NULL, + "value" TEXT NOT NULL, + "source_hash" TEXT, + "origin" "translation_origin", + + CONSTRAINT "translation_strings_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "jurisdiction_content_jurisdiction_id_language_key" ON "jurisdiction_content"("jurisdiction_id", "language"); + +-- CreateIndex +-- NULLS NOT DISTINCT (hand-added; Prisma cannot express it in the schema) so base rows (null +-- jurisdiction_id and site) and global Partners rows (null jurisdiction_id) cannot be duplicated. +-- Requires Postgres 15+. +CREATE UNIQUE INDEX "translation_strings_jurisdiction_id_language_site_key_key" ON "translation_strings"("jurisdiction_id", "language", "site", "key") NULLS NOT DISTINCT; + +-- AddForeignKey +ALTER TABLE "jurisdiction_content" ADD CONSTRAINT "jurisdiction_content_jurisdiction_id_fkey" FOREIGN KEY ("jurisdiction_id") REFERENCES "jurisdictions"("id") ON DELETE CASCADE ON UPDATE NO ACTION; + +-- AddForeignKey +ALTER TABLE "translation_strings" ADD CONSTRAINT "translation_strings_jurisdiction_id_fkey" FOREIGN KEY ("jurisdiction_id") REFERENCES "jurisdictions"("id") ON DELETE NO ACTION ON UPDATE NO ACTION; diff --git a/api/prisma/schema.prisma b/api/prisma/schema.prisma index b24800c215..b24effc367 100644 --- a/api/prisma/schema.prisma +++ b/api/prisma/schema.prisma @@ -779,6 +779,27 @@ model HouseholdMemberSnapshot { } // Jurisdiction Section +model JurisdictionContent { + id String @id() @default(dbgenerated("uuid_generate_v4()")) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(6) + + jurisdictionId String @map("jurisdiction_id") @db.Uuid + language LanguagesEnum + + // Typed JSON documents; rich-text bodies are sanitized HTML. + footer Json? + faq Json? + resources Json? + disclaimers Json? + contact Json? + + jurisdictions Jurisdictions @relation(fields: [jurisdictionId], references: [id], onDelete: Cascade, onUpdate: NoAction) + + @@unique([jurisdictionId, language]) + @@map("jurisdiction_content") +} + model Jurisdictions { id String @id() @default(dbgenerated("uuid_generate_v4()")) @db.Uuid createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6) @@ -818,12 +839,14 @@ model Jurisdictions { agency Agency[] amiCharts AmiChart[] featureFlags FeatureFlags[] + jurisdictionContent JurisdictionContent[] listings Listings[] listingSnapshots ListingSnapshot[] multiselectQuestions MultiselectQuestions[] properties Properties[] reservedCommunityTypes ReservedCommunityTypes[] translations Translations[] + translationStrings TranslationStrings[] user_accounts UserAccounts[] userAccountSnapshot UserAccountSnapshot[] @@ -1726,6 +1749,26 @@ model ScriptRuns { } // Translation Section +model TranslationStrings { + id String @id() @default(dbgenerated("uuid_generate_v4()")) @db.Uuid + createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6) + updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamp(6) + + jurisdictionId String? @map("jurisdiction_id") @db.Uuid + language LanguagesEnum + site SiteEnum? + key String + value String + sourceHash String? @map("source_hash") + origin TranslationOrigin? + + jurisdictions Jurisdictions? @relation(fields: [jurisdictionId], references: [id], onDelete: NoAction, onUpdate: NoAction) + + // The unique index is NULLS NOT DISTINCT; set in the migration, as Prisma cannot express it here. + @@unique([jurisdictionId, language, site, key]) + @@map("translation_strings") +} + model Translations { id String @id() @default(dbgenerated("uuid_generate_v4()")) @db.Uuid createdAt DateTime @default(now()) @map("created_at") @db.Timestamp(6) @@ -2375,6 +2418,20 @@ enum LanguagesEnum { @@map("languages_enum") } +enum SiteEnum { + public + partners + + @@map("site_enum") +} + +enum TranslationOrigin { + machine + human + + @@map("translation_origin") +} + enum ListingEventsTypeEnum { openHouse publicLottery