first build commit

This commit is contained in:
2026-04-19 00:44:43 -04:00
parent bc271b7ce1
commit 55debd082b
82 changed files with 6217 additions and 97 deletions

113
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,113 @@
generator client {
provider = "prisma-client"
output = "../src/generated/prisma"
}
datasource db {
provider = "postgresql"
}
model User {
id String @id @default(cuid())
email String @unique
passwordHash String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accounts Account[]
budgets Budget[]
}
enum AccountType {
BANK
CREDIT_CARD
}
model Account {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
name String
institution String?
type AccountType
currency String @default("USD")
currentBalanceCents Int @default(0)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
transactions Transaction[]
uploads CsvUpload[]
@@index([userId])
}
enum TransactionType {
DEBIT
CREDIT
}
model Transaction {
id String @id @default(cuid())
accountId String
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
uploadId String?
upload CsvUpload? @relation(fields: [uploadId], references: [id])
budgetId String?
budget Budget? @relation(fields: [budgetId], references: [id], onDelete: SetNull)
date DateTime
description String
amountCents Int
type TransactionType
category String?
notes String?
dedupeHash String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([dedupeHash])
@@index([accountId, date])
@@index([date])
@@index([budgetId])
}
model Budget {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
name String
limitCents Int?
color String?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
transactions Transaction[]
@@index([userId])
}
model CsvUpload {
id String @id @default(cuid())
accountId String
account Account @relation(fields: [accountId], references: [id])
fileName String
rowCount Int
importedCount Int
skippedCount Int
status String
errorMessage String?
uploadedAt DateTime @default(now())
transactions Transaction[]
@@index([accountId])
}
model BalanceSnapshot {
id String @id @default(cuid())
accountId String
year Int
month Int
balanceCents Int
computedAt DateTime @default(now())
@@unique([accountId, year, month])
@@index([year, month])
}

31
prisma/seed.ts Normal file
View File

@@ -0,0 +1,31 @@
import { Pool } from 'pg'
import { PrismaPg } from '@prisma/adapter-pg'
import { PrismaClient } from '../src/generated/prisma/client'
import bcrypt from 'bcryptjs'
const pool = new Pool({ connectionString: process.env.DATABASE_URL })
const adapter = new PrismaPg(pool)
const prisma = new PrismaClient({ adapter })
async function main() {
const email = process.env.SEED_EMAIL
const password = process.env.SEED_PASSWORD
if (!email || !password) {
throw new Error('SEED_EMAIL and SEED_PASSWORD must be set in .env')
}
const passwordHash = await bcrypt.hash(password, 12)
const user = await prisma.user.upsert({
where: { email },
update: { passwordHash },
create: { email, passwordHash },
})
console.log(`Seeded user: ${user.email}`)
}
main()
.catch(console.error)
.finally(() => prisma.$disconnect())