PAGE_CSS carried an unconditional `@media (prefers-color-scheme: dark)` block that redefined --bg, --surface, --text and --border. The merchant theme override only sets accent, button and typography tokens, so a visitor whose OS is in dark mode saw a dark card with the merchant's button colour on it, and no setting could change that. The form is rendered in a modal on top of the shop theme, which the app cannot read and which is almost always light. Move the dark palette out of PAGE_CSS into DARK_VARS and let renderShell apply it according to a new "themeScheme" setting: light (default), dark, or auto (follows prefers-color-scheme, the previous behaviour). The cascade is now base light palette -> chosen scheme -> merchant override, so custom accent and button colours win under either scheme. `color-scheme` and its meta tag follow the same setting, which keeps the native controls consistent. Existing rows have themeScheme NULL and fall back to the light default. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Mv83a29B4eFv5ixoj6PoE1
179 lines
5.2 KiB
Plaintext
179 lines
5.2 KiB
Plaintext
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Session — used by @shopify/shopify-app-session-storage-prisma.
|
|
// DO NOT change the shape of this model (the session storage depends on it).
|
|
// ---------------------------------------------------------------------------
|
|
model Session {
|
|
id String @id
|
|
shop String
|
|
state String
|
|
isOnline Boolean @default(false)
|
|
scope String?
|
|
expires DateTime?
|
|
accessToken String
|
|
userId BigInt?
|
|
firstName String?
|
|
lastName String?
|
|
email String?
|
|
accountOwner Boolean @default(false)
|
|
locale String?
|
|
collaborator Boolean? @default(false)
|
|
emailVerified Boolean? @default(false)
|
|
refreshToken String?
|
|
refreshTokenExpires DateTime?
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Multi-tenant app models. Every tenant-scoped row carries `shop` + an index
|
|
// on it (public-grade isolation from day 1, even with only 2-3 custom stores).
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Per-shop merchant configuration for the withdrawal button/flow.
|
|
model Settings {
|
|
id String @id @default(cuid())
|
|
shop String @unique
|
|
buttonLabel String @default("Recedere dal contratto qui")
|
|
confirmLabel String @default("Conferma recesso")
|
|
brandPrimaryColor String?
|
|
returnAddress String?
|
|
defaultWindowDays Int @default(14)
|
|
withdrawalInfoText String?
|
|
emailSubject String?
|
|
emailIntro String?
|
|
emailNote String?
|
|
notifyEnabled Boolean @default(true)
|
|
notifyEmail String?
|
|
tagEnabled Boolean @default(true)
|
|
enforceWindow Boolean @default(false)
|
|
enforceExclusions Boolean @default(false)
|
|
stateAwareEmail Boolean @default(true)
|
|
autoCancelUnfulfilled Boolean @default(false)
|
|
returnAtCustomerExpense Boolean @default(true)
|
|
returnInstructions String? // deprecato: sostituito da opTextShipped
|
|
opTextUnfulfilled String?
|
|
opTextShipped String?
|
|
smtpHost String?
|
|
smtpPort Int?
|
|
smtpUser String?
|
|
smtpPass String? // cifrato AES-256-GCM (mai in chiaro)
|
|
smtpSecure Boolean @default(false)
|
|
smtpFrom String?
|
|
// Motore di stile del form (livello 1 = token, livello 3 = CSS custom).
|
|
themeAccent String?
|
|
themeButtonBg String?
|
|
themeButtonText String?
|
|
themeRadius Int?
|
|
themeFont String?
|
|
themeWidth Int?
|
|
// "light" | "dark" | "auto". NULL = default applicativo (light).
|
|
themeScheme String?
|
|
themeCustomCss String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([shop])
|
|
}
|
|
|
|
// Art. 59 exclusions (made-to-order, perishable, sealed-for-hygiene, etc.).
|
|
model ExclusionRule {
|
|
id String @id @default(cuid())
|
|
shop String
|
|
scope ExclusionScope
|
|
targetId String?
|
|
reason ExclusionReason
|
|
active Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([shop])
|
|
}
|
|
|
|
// A withdrawal (recesso) statement submitted by a consumer.
|
|
model WithdrawalRequest {
|
|
id String @id @default(cuid())
|
|
shop String
|
|
orderId String
|
|
orderName String?
|
|
customerName String
|
|
email String
|
|
statementText String
|
|
transmittedAt DateTime // legal timestamp of transmission (Art. 54-bis)
|
|
locale String?
|
|
channel WithdrawalChannel
|
|
productType String?
|
|
status WithdrawalStatus @default(RECEIVED)
|
|
receiptSentAt DateTime?
|
|
computedDeadline DateTime?
|
|
shopifyReturnId String? // GID del Reso Shopify creato (se ordine evaso)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([shop])
|
|
@@index([shop, orderId])
|
|
}
|
|
|
|
// Append-only audit trail (burden of proof — Art. 54-bis / R6). No updatedAt.
|
|
model AuditLog {
|
|
id String @id @default(cuid())
|
|
shop String
|
|
event String
|
|
payloadHash String?
|
|
detail String?
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([shop])
|
|
}
|
|
|
|
// Webhook idempotency ledger.
|
|
model WebhookEvent {
|
|
id String @id @default(cuid())
|
|
shop String
|
|
topic String
|
|
webhookId String? @unique
|
|
receivedAt DateTime @default(now())
|
|
processed Boolean @default(false)
|
|
|
|
@@index([shop])
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Enums
|
|
// ---------------------------------------------------------------------------
|
|
|
|
enum ExclusionScope {
|
|
PRODUCT
|
|
COLLECTION
|
|
TAG
|
|
ALL
|
|
}
|
|
|
|
enum ExclusionReason {
|
|
CUSTOM
|
|
PERISHABLE
|
|
HYGIENE
|
|
OTHER
|
|
}
|
|
|
|
enum WithdrawalChannel {
|
|
GUEST
|
|
ACCOUNT
|
|
}
|
|
|
|
enum WithdrawalStatus {
|
|
RECEIVED
|
|
ACKNOWLEDGED
|
|
GOODS_PENDING
|
|
CLOSED
|
|
REJECTED
|
|
}
|