Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions docs/DATABASE_SCHEMA.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
## Scaling Strategies

### Vertical Scaling
- Increase CPU, RAM, and disk IOPS on the PostgreSQL server for higher throughput.
- Adjust `connection_limit` in the DATABASE_URL to match available resources.

### Horizontal Scaling
- Use read replicas for scaling read-heavy workloads. Configure Prisma to use replicas for read queries (future enhancement).
- For global scale, consider managed PostgreSQL services (e.g., AWS RDS, GCP Cloud SQL) with multi-region support.

### Connection Pool Tuning
- Tune `connection_limit` and `pool_timeout` in the DATABASE_URL for optimal pool size.
- Monitor active connections and adjust pool size as needed.

### Caching
- Use Redis for caching frequently accessed data and query results.
- Cache count queries and first-page results for large datasets.

### Partitioning and Sharding (Advanced)
- For very large tables, consider PostgreSQL table partitioning.
- Sharding is not natively supported by Prisma, but can be implemented at the application layer if needed.

### High Availability & Failover
- Use managed PostgreSQL with automatic failover and backups.
- Regularly test backup and restore procedures (see backup.sh and restore.sh).

### Monitoring
- Monitor query performance and slow queries using Prisma logs and PostgreSQL tools (pg_stat_statements).
- Set up external monitoring (e.g., Prometheus, Grafana) for database metrics.

// See SETUP.md for more performance and monitoring tips.
# PropChain Database Schema Documentation

## Overview
Expand Down
57 changes: 36 additions & 21 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema


// Prisma client generator
generator client {
provider = "prisma-client-js"
}


// Database connection configuration
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}

model User {
id String @id @default(cuid())
email String @unique
walletAddress String? @unique @map("wallet_address")
email String @unique // Unique index for fast user lookup by email
walletAddress String? @unique @map("wallet_address") // Unique index for wallet address
role UserRole @default(USER)
roleId String? @map("role_id")
password String?
Expand All @@ -27,10 +31,13 @@ model User {
roleChanges RoleChangeLog[]
documents Document[]

@@index([email])
@@index([walletAddress])
@@index([role])
@@index([createdAt])
// Indexes for common query patterns
@@index([email]) // For searching users by email
@@index([walletAddress]) // For searching users by wallet address
@@index([role]) // For filtering users by role
@@index([createdAt]) // For sorting/filtering by creation date
// Consider adding an index on isVerified if you often filter by verification status
@@index([isVerified])
@@map("users")
}

Expand Down Expand Up @@ -68,12 +75,14 @@ model Property {
latitude Float?
longitude Float?


@@index([latitude, longitude])
@@index([ownerId])
@@index([status])
@@index([createdAt])
@@index([location])
// Indexes for geospatial queries and filtering
@@index([latitude, longitude]) // For location-based queries
@@index([ownerId]) // For filtering properties by owner
@@index([status]) // For filtering by property status
@@index([createdAt]) // For sorting/filtering by creation date
@@index([location]) // For searching/filtering by location
// Consider adding an index on price if you often filter/sort by price
@@index([price])
@@map("properties")
}

Expand All @@ -90,7 +99,10 @@ model PropertyValuation {
createdAt DateTime @default(now())

property Property @relation(fields: [propertyId], references: [id], onDelete: Cascade)


// Index for fast lookup by property and date
@@index([propertyId])
@@index([valuationDate])
@@map("property_valuations")
}

Expand All @@ -117,17 +129,20 @@ model Transaction {
platformFee Decimal?
disputeReason String?

property Property? @relation(fields: [propertyId], references: [id], onDelete: SetNull)
property Property? @relation(fields: [propertyId], references: [id], onDelete: SetNull)
recipient User? @relation("UserTransactions", fields: [toAddress], references: [walletAddress])
documents Document[]

@@index([buyerId])
@@index([sellerId])
@@index([fromAddress])
@@index([toAddress])
@@index([status])
@@index([createdAt])
@@index([propertyId])
// Indexes for common transaction queries
@@index([buyerId]) // For filtering by buyer
@@index([sellerId]) // For filtering by seller
@@index([fromAddress]) // For filtering by sender
@@index([toAddress]) // For filtering by recipient
@@index([status]) // For filtering by transaction status
@@index([createdAt]) // For sorting/filtering by creation date
@@index([propertyId]) // For filtering by property
// Consider adding an index on txHash if you often search by transaction hash
@@index([txHash])
@@map("transactions")
}

Expand Down
31 changes: 23 additions & 8 deletions src/database/prisma/prisma.service.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@

// PrismaService manages the PrismaClient lifecycle and database connection pooling.
// Connection pooling is configured via the DATABASE_URL environment variable.
// Example: postgresql://user:pass@host:5432/db?connection_limit=10&pool_timeout=30
// See docs/DATABASE_SCHEMA.md for recommended settings.
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
import { PrismaClient, Prisma } from '@prisma/client';
import { ConfigService } from '@nestjs/config';
import { StructuredLoggerService } from '../../common/logging/logger.service';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
/**
* PrismaService constructor
* - Configures PrismaClient with connection pooling via DATABASE_URL
* - See docs/DATABASE_SCHEMA.md for recommended pooling settings
* - Logs queries, errors, and warnings
*/
constructor(
private readonly configService: ConfigService,
private readonly logger: StructuredLoggerService,
) {
// Get the database URL from environment/config
const databaseUrl = configService.get<string>('DATABASE_URL');

// Connection pooling configuration via URL parameters
// Prisma uses the connection URL to configure pooling
// Example: postgresql://user:pass@host:5432/db?connection_limit=10&pool_timeout=30
super({
Expand All @@ -30,17 +41,21 @@ export class PrismaService extends PrismaClient implements OnModuleInit, OnModul
this.logger.setContext('PrismaService');
}

/**
* Initialize Prisma connection and enable query performance monitoring.
* Logs query durations and parameters for performance analysis.
*/
async onModuleInit() {
this.logger.log('Connecting to database...');

if (this.configService.get<string>('NODE_ENV') === 'development') {
(this as any).$on('query', (e: any) => {
this.logger.logDatabase('query', e.duration, {
query: e.query,
params: e.params,
});
// Enable query performance monitoring in all environments
(this as any).$on('query', (e: any) => {
// Log query duration, SQL, and parameters
this.logger.logDatabase('query', e.duration, {
query: e.query,
params: e.params,
});
}
});

await this.$connect();
this.logger.log('Database connection established');
Expand Down
Loading