Skip to content

Scalability Guide

Enterprise scalability patterns for global deployment

Current Stack (February 2026)

LayerTechnologyVersion
FrontendNext.js (Azure Static Web Apps)15.5.12
BackendNestJS (Azure Container Apps)11.x
DatabaseMongoDB Atlas7.x
StorageAzure Blob Storage-
CDNAzure Front Door (optional)-
CI/CDGitHub Actions, Node.js 22-

Current Architecture

┌──────────────┐     ┌──────────────────┐     ┌──────────────┐
│   Frontend   │────▶│  Azure Container │────▶│   MongoDB    │
│  (Static)    │     │  Apps (Backend)  │     │   Atlas      │
└──────────────┘     └──────────────────┘     └──────────────┘

                     ┌────────┴────────┐
                     ▼                 ▼
              ┌────────────┐   ┌────────────────┐
              │ Azure Blob │   │   Azure CDN    │
              │  Storage   │   │   (Optional)   │
              └────────────┘   └────────────────┘

Horizontal Scaling

Container Apps Auto-scaling

Azure Container Apps supports automatic scaling:

bash
az containerapp update \
  --name ctrl-audio-backend \
  --resource-group Sonnance-WebApp \
  --min-replicas 1 \
  --max-replicas 10 \
  --scale-rule-name http-rule \
  --scale-rule-type http \
  --scale-rule-http-concurrency 100

Scaling Triggers

MetricRecommendation
HTTP RequestsScale at 100 concurrent connections
MemoryScale at 70% memory utilization
Queue DepthFor background jobs (future)

Database Optimization

MongoDB Indexes

Ensure indexes exist for common queries:

javascript
// Artist Space queries
db.artistspaces.createIndex({ owner: 1 });
db.artistspaces.createIndex({ "collaborators.user": 1 });

// Track queries
db.tracks.createIndex({ project: 1, isDeleted: 1 });
db.tracks.createIndex({ owner: 1, createdAt: -1 });

// Search optimization
db.artistspaces.createIndex({ name: "text" });
db.projects.createIndex({ name: "text" });
db.tracks.createIndex({ name: "text" });

Aggregation Pipeline Optimization

typescript
// Use $project early to reduce document size
const pipeline = [
  { $match: { owner: userId, isDeleted: false } },
  { $project: { name: 1, image: 1, updatedAt: 1 } }, // Early projection
  { $sort: { updatedAt: -1 } },
  { $limit: 50 }
];

CDN for Global Distribution

Azure CDN Setup

Run the setup script:

bash
cd infrastructure
chmod +x setup-cdn.sh
./setup-cdn.sh

CDN Benefits

MetricWithout CDNWith CDN
Latency (EU)50-100ms10-20ms
Latency (US)150-200ms20-30ms
Bandwidth costs$0.087/GB$0.081/GB
Cache hit ratio0%85-95%

CDN URL Integration

typescript
// Environment variable
NEXT_PUBLIC_CDN_URL=https://sonnance-images.azureedge.net

// Replace storage URLs with CDN
const cdnUrl = imageUrl.replace(
  'sonnancewebappstorage00.blob.core.windows.net',
  process.env.CDN_HOSTNAME
);

Mobile App API Considerations

Pagination

Always use cursor-based pagination for mobile:

typescript
// Cursor-based (recommended)
GET /tracks?cursor=507f1f77bcf86cd799439011&limit=20

// Response
{
  items: [...],
  nextCursor: "507f1f77bcf86cd799439012",
  hasMore: true
}

Response Compression

Enable gzip compression:

typescript
import * as compression from 'compression';
app.use(compression());

Efficient Endpoints for Mobile

typescript
// ✅ Good - Single request with embedded data
GET /artist-space/:id/full
// Returns: space + projects + recent tracks

// ❌ Avoid - Multiple round trips
GET /artist-space/:id
GET /projects?spaceId=xxx
GET /tracks?projectId=xxx

Image Optimization for Mobile

Return appropriate image variants:

typescript
// Mobile clients request smaller images
GET /artist/:id?imageSize=thumbnail

// Responsive image URLs in responses
{
  image: {
    thumbnail: "https://cdn/.../thumb.webp",  // 150x150
    medium: "https://cdn/.../medium.webp",    // 600px
    original: "https://cdn/.../original.webp"
  }
}

Caching Strategy

API Response Caching

typescript
// Redis caching (recommended for future)
import { CacheModule } from '@nestjs/cache-manager';
import * as redisStore from 'cache-manager-redis-store';

CacheModule.register({
  store: redisStore,
  host: 'localhost',
  ttl: 300, // 5 minutes
});

Cache Invalidation

Invalidate on mutations:

typescript
@Injectable()
export class ArtistService {
  async update(id: string, dto: UpdateDto) {
    await this.cacheManager.del(`artist:${id}`);
    return this.repository.update(id, dto);
  }
}

Background Jobs

Current: @nestjs/schedule

typescript
// Trash cleanup runs periodically
@Cron('0 0 * * *') // Daily at midnight
async deleteOldItems() {
  // Delete items older than 30 days
}

Future: Dedicated Queue (BullMQ)

For heavy processing (audio transcoding, batch operations):

typescript
import { BullModule } from '@nestjs/bull';

@Module({
  imports: [
    BullModule.registerQueue({
      name: 'audio-processing',
    }),
  ],
})

Monitoring & Observability

Azure Application Insights

typescript
import * as appInsights from 'applicationinsights';

appInsights.setup(process.env.APPINSIGHTS_INSTRUMENTATIONKEY)
  .setAutoCollectRequests(true)
  .setAutoCollectDependencies(true)
  .start();

Health Checks

typescript
import { HealthModule, HealthCheckService } from '@nestjs/terminus';

@Controller('health')
export class HealthController {
  @Get()
  @HealthCheck()
  check() {
    return this.health.check([
      () => this.db.pingCheck('mongodb'),
      () => this.storage.pingCheck('azure-blob'),
    ]);
  }
}

Scaling Roadmap

PhaseFeatureEffortImpact
1Azure CDN1 hourHigh
2MongoDB indexes2 hoursHigh
3Response compression30 minMedium
4Application Insights2 hoursMedium
5Redis caching1 dayHigh
6BullMQ for jobs2 daysMedium

Last Updated: February 2026

Ctrl-Audio Platform Documentation