- JWT authentication with Supabase integration - Role-based access control (Admin, Owner, Staff, Auditor) - Universal database adapter (Prisma/Supabase/MongoDB support) - User management with hierarchical permissions - Redis caching service (configured but optional) - Comprehensive API documentation - Production-ready NestJS architecture - Migration scripts for provider switching - Swagger/OpenAPI documentation
145 lines
3.2 KiB
Markdown
145 lines
3.2 KiB
Markdown
# Database Migration Scenarios
|
|
|
|
## Scenario 1: PostgreSQL → PostgreSQL (Different Provider)
|
|
**Examples**: Supabase → AWS RDS, Google Cloud SQL, Railway, Neon, PlanetScale
|
|
|
|
### What Changes:
|
|
- ✅ Connection string only
|
|
- ✅ Keep all Prisma code unchanged
|
|
- ✅ Keep all SQL queries unchanged
|
|
|
|
### Migration Steps:
|
|
```bash
|
|
# 1. Update connection string
|
|
DATABASE_URL="postgresql://user:pass@new-provider.com:5432/db"
|
|
|
|
# 2. Run Prisma migration
|
|
npx prisma migrate deploy
|
|
|
|
# 3. Update environment variables
|
|
SUPABASE_URL="" # Remove
|
|
SUPABASE_SERVICE_ROLE_KEY="" # Remove
|
|
```
|
|
|
|
### Code Changes Required:
|
|
```typescript
|
|
// Before (Supabase)
|
|
const { data } = await this.supabase.from('users').select('*');
|
|
|
|
// After (Any PostgreSQL + Prisma)
|
|
const data = await this.prisma.user.findMany();
|
|
```
|
|
|
|
**Effort**: 1-2 days
|
|
**Risk**: Very Low
|
|
|
|
---
|
|
|
|
## Scenario 2: PostgreSQL → MySQL/MariaDB
|
|
**Examples**: Supabase → AWS RDS MySQL, PlanetScale MySQL
|
|
|
|
### What Changes:
|
|
- ⚠️ Schema syntax differences
|
|
- ⚠️ Data type mappings
|
|
- ✅ Prisma handles most differences
|
|
|
|
### Migration Steps:
|
|
```prisma
|
|
// Update datasource in schema.prisma
|
|
datasource db {
|
|
provider = "mysql" // Changed from postgresql
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// Some field types may need updates
|
|
model User {
|
|
id String @id @default(cuid()) // uuid() → cuid() for MySQL
|
|
// ... rest unchanged
|
|
}
|
|
```
|
|
|
|
**Effort**: 3-5 days
|
|
**Risk**: Low-Medium
|
|
|
|
---
|
|
|
|
## Scenario 3: PostgreSQL → MongoDB
|
|
**Examples**: Supabase → MongoDB Atlas, AWS DocumentDB
|
|
|
|
### What Changes:
|
|
- ❌ Complete schema redesign
|
|
- ❌ Relational → Document model
|
|
- ❌ All queries need rewriting
|
|
|
|
### Migration Complexity:
|
|
```typescript
|
|
// Before (Relational)
|
|
const user = await this.prisma.user.findUnique({
|
|
where: { id },
|
|
include: { receipts: true, staff: true }
|
|
});
|
|
|
|
// After (Document)
|
|
const user = await this.mongodb.collection('users').findOne({
|
|
_id: ObjectId(id)
|
|
});
|
|
// Receipts and staff would be embedded documents or separate collections
|
|
```
|
|
|
|
**Effort**: 2-4 weeks
|
|
**Risk**: High
|
|
|
|
---
|
|
|
|
## Scenario 4: Keep Database, Replace Supabase Services
|
|
**Examples**: Keep PostgreSQL, replace Auth/Storage with AWS/Firebase
|
|
|
|
### Service Replacements:
|
|
|
|
#### Authentication:
|
|
```typescript
|
|
// Before: Supabase Auth
|
|
await supabase.auth.signInWithOtp({ email });
|
|
|
|
// After: AWS Cognito
|
|
await cognito.initiateAuth({ email });
|
|
|
|
// After: Firebase Auth
|
|
await firebase.auth().sendSignInLinkToEmail(email);
|
|
|
|
// After: Auth0
|
|
await auth0.passwordlessStart({ email });
|
|
```
|
|
|
|
#### File Storage:
|
|
```typescript
|
|
// Before: Supabase Storage
|
|
await supabase.storage.from('receipts').upload(fileName, file);
|
|
|
|
// After: AWS S3
|
|
await s3.upload({ Bucket: 'receipts', Key: fileName, Body: file });
|
|
|
|
// After: Google Cloud Storage
|
|
await storage.bucket('receipts').file(fileName).save(file);
|
|
|
|
// After: Cloudinary
|
|
await cloudinary.uploader.upload(file, { public_id: fileName });
|
|
```
|
|
|
|
#### Real-time:
|
|
```typescript
|
|
// Before: Supabase Realtime
|
|
supabase.from('users').on('*', callback).subscribe();
|
|
|
|
// After: Socket.IO
|
|
io.on('user_updated', callback);
|
|
|
|
// After: AWS AppSync
|
|
await appSync.subscribe({ subscription: USER_UPDATED });
|
|
|
|
// After: Pusher
|
|
pusher.subscribe('users').bind('updated', callback);
|
|
```
|
|
|
|
**Effort**: 1-3 weeks per service
|
|
**Risk**: Medium |