Conceptual Architecture
Database Architecture
Our system uses a multi-database approach, combining PostgreSQL for relational data and Firestore for real-time and document-based data needs.
Primary Database: PostgreSQL
We use Google Cloud SQL for PostgreSQL as our primary database, handling all critical transactional data.
Key Characteristics
PostgreSQL Benefits
- Strong ACID compliance
- Rich querying capabilities
- Robust transaction support
- Excellent data integrity
Core Data Models
// User Management
model User {
id String @id
email String @unique
hashedPassword String?
role UserRole
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
apiKey ApiKey?
agentProfile AgentProfile?
}
// Agent Profiles
model AgentProfile {
id String @id
userId String @unique
companyName String?
webhookUrl String?
webhookSecret String?
devices Device[]
transactions Transaction[]
payouts Payout[]
restrictedFeatures String[]
}
// Device Management
model Device {
id String @id
name String
deviceIdentifier String @unique
agentProfileId String
apiKey String?
status String
lastSeen DateTime?
transactions Transaction[]
payouts Payout[]
}
// Transactions
model Transaction {
id String @id
type TransactionType
status TransactionStatus
amount Decimal
currency String
bankTransactionId String?
serviceFee Decimal?
netAmount Decimal?
metadata Json?
webhookStatus String?
webhookAttempts Int
}
Database Design Principles
Normalization
- Properly normalized tables
- Appropriate foreign key relationships
- Indexes for query optimization
Data Integrity
- Constraints enforcement
- Referential integrity
- Check constraints for business rules
Performance
- Strategic indexing
- Materialized views where needed
- Query optimization
Secondary Database: Firestore
We use Firestore for specific use cases requiring real-time updates or document-based storage.
Use Cases
- Device Status Tracking
interface DeviceStatus {
deviceId: string;
status: 'ONLINE' | 'OFFLINE' | 'ERROR';
lastHeartbeat: Timestamp;
currentError?: string;
}
- Real-time Updates
interface TransactionUpdate {
transactionId: string;
status: string;
timestamp: Timestamp;
metadata: Record<string, any>;
}
Firestore Collections
device_status
: Real-time device statustransaction_updates
: Live transaction feedstemporary_session_data
: Short-lived session info
Data Access Patterns
Service-Specific Access
Each microservice has specific data access patterns:
User Service
- User CRUD operations
- Profile management
- API key operations
Transaction Service
- Transaction creation and updates
- Status tracking
- Fee calculations
Device Service
- Device registration
- Status updates
- Credential management
Data Access Layer
We use Prisma ORM for PostgreSQL access:
// Example service data access
export class UserRepository {
constructor(private prisma: PrismaClient) {}
async createUser(data: CreateUserDTO): Promise<User> {
return this.prisma.user.create({
data: {
...data,
apiKey: {
create: {
key: generateApiKey(),
},
},
},
include: {
apiKey: true,
},
});
}
}
Data Migration Strategy
Schema Changes
- Use Prisma migrations
- Version control for schemas
- Backward compatibility
Data Migration
- Staged migrations
- Data validation
- Rollback procedures
Backup and Recovery
PostgreSQL Backup
- Automated daily backups
- Point-in-time recovery
- Geographic replication
Firestore Backup
- Regular exports
- Backup retention policy
- Recovery procedures
Performance Optimization
Indexing Strategy
- Carefully planned indexes
- Regular index maintenance
- Query performance monitoring
Caching Layer
- Redis for frequent queries
- Cache invalidation strategy
- Cache hit ratio monitoring