349 lines
9.6 KiB
Plaintext
349 lines
9.6 KiB
Plaintext
generator client {
|
|
provider = "prisma-client"
|
|
output = "../generated/prisma"
|
|
moduleFormat = "cjs"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
}
|
|
|
|
model User {
|
|
id String @id
|
|
email String @unique
|
|
passwordHash String
|
|
bankCards BankCard[]
|
|
expenseCategories ExpenseCategory[]
|
|
bankCardOperations BankCardOperation[]
|
|
sessions Session[]
|
|
tbankConnection TbankConnection?
|
|
tbankValueHistory TbankPortfolioValueHistory[]
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
model TbankConnection {
|
|
userId String @unique
|
|
encryptedToken String
|
|
connectedAt DateTime
|
|
revision String @default(uuid())
|
|
invalidToken Boolean @default(false)
|
|
membershipAt DateTime?
|
|
membershipRevision Int @default(0)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
accounts TbankAccount[]
|
|
forecasts TbankForecast[]
|
|
work TbankSyncWork[]
|
|
|
|
@@unique([userId, revision])
|
|
}
|
|
|
|
model TbankAccount {
|
|
userId String
|
|
revision String
|
|
accountId String
|
|
type String
|
|
name String
|
|
openedOn String?
|
|
upstreamOrder Int
|
|
operationsRevision Int @default(0)
|
|
historyFrom DateTime?
|
|
historyBoundary String @default("unknown")
|
|
connection TbankConnection @relation(fields: [userId, revision], references: [userId, revision], onDelete: Cascade, onUpdate: Restrict)
|
|
portfolio TbankPortfolio?
|
|
operations TbankOperation[]
|
|
coverage TbankOperationCoverage[]
|
|
|
|
@@id([userId, revision, accountId])
|
|
}
|
|
|
|
model TbankPortfolio {
|
|
userId String
|
|
revision String
|
|
accountId String
|
|
payload Json
|
|
mappingVersion Int @default(1)
|
|
fetchedAt DateTime
|
|
dataRevision Int @default(1)
|
|
account TbankAccount @relation(fields: [userId, revision, accountId], references: [userId, revision, accountId], onDelete: Cascade, onUpdate: Restrict)
|
|
|
|
@@id([userId, revision, accountId])
|
|
}
|
|
|
|
// Account valuation history survives connection replacement and stays hidden
|
|
// until the current connection confirms the account again.
|
|
model TbankPortfolioValueHistory {
|
|
userId String
|
|
accountId String
|
|
deletedAt DateTime?
|
|
updatedAt DateTime @updatedAt
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
points TbankPortfolioValuePoint[]
|
|
|
|
@@id([userId, accountId])
|
|
}
|
|
|
|
// One row per currency of a fully valued successful portfolio attempt.
|
|
model TbankPortfolioValuePoint {
|
|
userId String
|
|
accountId String
|
|
attemptId String
|
|
currency String
|
|
value String
|
|
capturedAt DateTime
|
|
createdAt DateTime @default(now())
|
|
history TbankPortfolioValueHistory @relation(fields: [userId, accountId], references: [userId, accountId], onDelete: Cascade, onUpdate: Restrict)
|
|
|
|
@@id([userId, accountId, attemptId, currency])
|
|
@@index([userId, accountId, capturedAt])
|
|
}
|
|
|
|
model TbankOperation {
|
|
userId String
|
|
revision String
|
|
accountId String
|
|
brokerOperationId String
|
|
occurredAt DateTime
|
|
instrumentUid String?
|
|
category String
|
|
payload Json
|
|
mappingVersion Int @default(1)
|
|
account TbankAccount @relation(fields: [userId, revision, accountId], references: [userId, revision, accountId], onDelete: Cascade, onUpdate: Restrict)
|
|
|
|
@@id([userId, revision, accountId, brokerOperationId])
|
|
@@index([userId, revision, accountId, occurredAt, brokerOperationId])
|
|
@@index([userId, revision, accountId, instrumentUid, occurredAt])
|
|
@@index([userId, revision, accountId, category, occurredAt])
|
|
}
|
|
|
|
model TbankOperationCoverage {
|
|
userId String
|
|
revision String
|
|
accountId String
|
|
instrumentPredicate String @default("")
|
|
from DateTime
|
|
to DateTime
|
|
fetchedAt DateTime
|
|
asOf DateTime
|
|
account TbankAccount @relation(fields: [userId, revision, accountId], references: [userId, revision, accountId], onDelete: Cascade, onUpdate: Restrict)
|
|
|
|
@@id([userId, revision, accountId, instrumentPredicate, from, to])
|
|
}
|
|
|
|
model TbankForecast {
|
|
userId String
|
|
revision String
|
|
scopeKey String
|
|
membershipRevision Int
|
|
payload Json
|
|
dependencyRevisions Json
|
|
sourceTimestamps Json
|
|
calculatedAt DateTime
|
|
dataRevision Int @default(1)
|
|
connection TbankConnection @relation(fields: [userId, revision], references: [userId, revision], onDelete: Cascade, onUpdate: Restrict)
|
|
|
|
@@id([userId, revision, scopeKey])
|
|
}
|
|
|
|
model TbankInstrument {
|
|
provider String
|
|
uid String
|
|
figi String?
|
|
ticker String?
|
|
instrumentType String
|
|
metadata Json
|
|
fetchedAt DateTime
|
|
dataRevision Int @default(1)
|
|
sources TbankInstrumentSource[]
|
|
candles TbankCandle[]
|
|
candleCoverage TbankCandleCoverage[]
|
|
|
|
@@id([provider, uid])
|
|
@@index([provider, figi])
|
|
@@index([provider, ticker, instrumentType])
|
|
}
|
|
|
|
model TbankCatalogDiscovery {
|
|
provider String
|
|
instrumentType String
|
|
query String
|
|
instrumentUids Json
|
|
fetchedAt DateTime
|
|
dataRevision Int @default(1)
|
|
|
|
@@id([provider, instrumentType, query])
|
|
}
|
|
|
|
// Empty and ambiguous successful UID/FIGI/ticker lookups are distinct from failures.
|
|
model TbankInstrumentLookup {
|
|
provider String
|
|
identifierType String
|
|
identifier String
|
|
matchedUids Json
|
|
fetchedAt DateTime
|
|
dataRevision Int @default(1)
|
|
|
|
@@id([provider, identifierType, identifier])
|
|
}
|
|
|
|
// Public per-instrument classification; no holdings or credentials.
|
|
model TbankInstrumentClassification {
|
|
provider String
|
|
instrumentKey String
|
|
sector String?
|
|
sectorFetchedAt DateTime?
|
|
assetUid String?
|
|
brandUid String?
|
|
brandName String?
|
|
brandFetchedAt DateTime?
|
|
|
|
@@id([provider, instrumentKey])
|
|
}
|
|
|
|
// Source records contain no holdings, personal estimates or credentials errors.
|
|
model TbankInstrumentSource {
|
|
provider String
|
|
instrumentUid String
|
|
source String
|
|
kind String
|
|
rangeKey String
|
|
payload Json
|
|
fetchedAt DateTime
|
|
dataRevision Int @default(1)
|
|
instrument TbankInstrument @relation(fields: [provider, instrumentUid], references: [provider, uid], onDelete: Cascade)
|
|
|
|
@@id([provider, instrumentUid, source, kind, rangeKey])
|
|
}
|
|
|
|
model TbankCandle {
|
|
provider String
|
|
instrumentUid String
|
|
interval String
|
|
time DateTime
|
|
close String
|
|
payload Json
|
|
isComplete Boolean
|
|
fetchedAt DateTime
|
|
instrument TbankInstrument @relation(fields: [provider, instrumentUid], references: [provider, uid], onDelete: Cascade)
|
|
|
|
@@id([provider, instrumentUid, interval, time])
|
|
}
|
|
|
|
model TbankCandleCoverage {
|
|
provider String
|
|
instrumentUid String
|
|
interval String
|
|
from DateTime
|
|
to DateTime
|
|
isComplete Boolean
|
|
fetchedAt DateTime
|
|
dataRevision Int @default(1)
|
|
instrument TbankInstrument @relation(fields: [provider, instrumentUid], references: [provider, uid], onDelete: Cascade)
|
|
|
|
@@id([provider, instrumentUid, interval, from, to])
|
|
}
|
|
|
|
model TbankSyncWork {
|
|
id String @id
|
|
userId String
|
|
revision String
|
|
scopeKey String
|
|
intent Json
|
|
state String
|
|
attemptId String
|
|
processRunId String
|
|
priority Int
|
|
progress Json
|
|
errorCode String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
connection TbankConnection @relation(fields: [userId, revision], references: [userId, revision], onDelete: Cascade, onUpdate: Restrict)
|
|
staged TbankSyncStage[]
|
|
|
|
@@unique([userId, revision, scopeKey])
|
|
@@index([userId, revision, state, priority])
|
|
@@unique([id, attemptId])
|
|
}
|
|
|
|
model TbankSyncStage {
|
|
workId String
|
|
attemptId String
|
|
sourceKey String
|
|
itemKey String
|
|
payload Json
|
|
work TbankSyncWork @relation(fields: [workId, attemptId], references: [id, attemptId], onDelete: Cascade, onUpdate: Restrict)
|
|
|
|
@@id([workId, attemptId, sourceKey, itemKey])
|
|
}
|
|
|
|
model Session {
|
|
id String @id
|
|
userId String
|
|
refreshTokenHash String
|
|
expiresAt DateTime
|
|
revokedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
}
|
|
|
|
model BankCard {
|
|
id String @id
|
|
userId String
|
|
name String
|
|
bankName String?
|
|
lastFour String?
|
|
paymentSystem String?
|
|
openingBalanceKopecks BigInt
|
|
openingDate String
|
|
version Int @default(1)
|
|
archivedAt DateTime?
|
|
createFingerprint String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
user User @relation(fields: [userId], references: [id], onDelete: Restrict)
|
|
operations BankCardOperation[] @relation("SourceCard")
|
|
incomingOperations BankCardOperation[] @relation("TargetCard")
|
|
@@index([userId])
|
|
}
|
|
model ExpenseCategory {
|
|
id String @id
|
|
userId String
|
|
name String
|
|
nameKey String
|
|
seedKey String?
|
|
version Int @default(1)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Restrict)
|
|
operations BankCardOperation[]
|
|
@@unique([userId, nameKey])
|
|
@@unique([userId, seedKey])
|
|
}
|
|
model BankCardOperation {
|
|
id String @id
|
|
userId String
|
|
kind String
|
|
cardId String
|
|
targetCardId String?
|
|
categoryId String?
|
|
originalExpenseId String?
|
|
amountKopecks BigInt
|
|
date String
|
|
description String?
|
|
version Int @default(1)
|
|
deletedAt DateTime?
|
|
createFingerprint String
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
user User @relation(fields: [userId], references: [id], onDelete: Restrict)
|
|
card BankCard @relation("SourceCard", fields: [cardId], references: [id], onDelete: Restrict)
|
|
targetCard BankCard? @relation("TargetCard", fields: [targetCardId], references: [id], onDelete: Restrict)
|
|
category ExpenseCategory? @relation(fields: [categoryId], references: [id], onDelete: Restrict)
|
|
originalExpense BankCardOperation? @relation("RefundExpense", fields: [originalExpenseId], references: [id], onDelete: Restrict, onUpdate: NoAction)
|
|
refunds BankCardOperation[] @relation("RefundExpense")
|
|
@@index([userId, cardId, date])
|
|
@@index([userId, targetCardId, date])
|
|
@@index([originalExpenseId])
|
|
}
|