Initial commit

This commit is contained in:
2026-03-10 21:30:52 -03:00
commit 72a4f0be26
145 changed files with 14881 additions and 0 deletions

View File

@@ -0,0 +1,154 @@
// Prisma schema for dwellops-platform
// Better Auth requires User, Session, Account, and Verification models
// with specific field names — do not rename them.
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
}
// ─── Better Auth required models ───────────────────────────────────────────
model User {
id String @id @default(cuid())
email String @unique
name String?
emailVerified Boolean @default(false)
image String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sessions Session[]
accounts Account[]
memberships Membership[]
@@map("users")
}
model Session {
id String @id
userId String
token String @unique
expiresAt DateTime
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ipAddress String?
userAgent String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("sessions")
}
model Account {
id String @id
userId String
accountId String
providerId String
accessToken String?
refreshToken String?
idToken String?
accessTokenExpiresAt DateTime?
refreshTokenExpiresAt DateTime?
scope String?
password String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("accounts")
}
model Verification {
id String @id
identifier String
value String
expiresAt DateTime
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("verifications")
}
// ─── HOA domain models ─────────────────────────────────────────────────────
/// A homeowners association managed by the platform.
/// In self-hosted mode there is typically one HOA per deployment,
/// but the schema supports multiple to enable future SaaS evolution.
model Hoa {
id String @id @default(cuid())
name String
slug String @unique
description String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
units Unit[]
memberships Membership[]
@@map("hoas")
}
/// A dwelling unit within an HOA (apartment, townhouse, lot, etc.).
model Unit {
id String @id @default(cuid())
hoaId String
identifier String
address String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
hoa Hoa @relation(fields: [hoaId], references: [id], onDelete: Cascade)
memberships Membership[]
@@unique([hoaId, identifier])
@@map("units")
}
/// Supported roles within an HOA.
enum Role {
ADMIN
BOARD_MEMBER
TREASURER
OWNER
TENANT
VIEWER
}
/// Connects a User to an HOA with a role, optionally scoped to a Unit.
model Membership {
id String @id @default(cuid())
userId String
hoaId String
unitId String?
role Role @default(OWNER)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
hoa Hoa @relation(fields: [hoaId], references: [id], onDelete: Cascade)
unit Unit? @relation(fields: [unitId], references: [id], onDelete: SetNull)
@@unique([userId, hoaId, unitId])
@@map("memberships")
}
/// Immutable audit log for important platform actions.
model AuditLog {
id String @id @default(cuid())
/// Nullable to support system-initiated actions.
userId String?
action String
entityType String
entityId String?
payload Json?
ipAddress String?
userAgent String?
createdAt DateTime @default(now())
@@map("audit_logs")
}

View File

@@ -0,0 +1,52 @@
import { PrismaClient } from '@prisma/client';
import { Pool } from 'pg';
import { PrismaPg } from '@prisma/adapter-pg';
const connectionString = process.env['DATABASE_URL'];
if (!connectionString) {
throw new Error('DATABASE_URL is required for seeding');
}
const pool = new Pool({ connectionString });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });
/**
* Seeds the local development database with minimal starter data.
* Not intended for production use.
*/
async function main(): Promise<void> {
console.log('Seeding database...');
const hoa = await prisma.hoa.upsert({
where: { slug: 'sunrise-ridge' },
create: {
name: 'Sunrise Ridge HOA',
slug: 'sunrise-ridge',
description: 'Development seed HOA',
},
update: {},
});
console.log(`HOA: ${hoa.name} (${hoa.id})`);
const unit = await prisma.unit.upsert({
where: { hoaId_identifier: { hoaId: hoa.id, identifier: '101' } },
create: {
hoaId: hoa.id,
identifier: '101',
address: '1 Sunrise Ridge Dr, Unit 101',
},
update: {},
});
console.log(`Unit: ${unit.identifier} (${unit.id})`);
console.log('Seeding complete.');
}
main()
.catch((err) => {
console.error(err);
process.exit(1);
})
.finally(() => prisma.$disconnect());