Assist_Design/apps/bff/src/modules/services/services.controller.ts

113 lines
4.3 KiB
TypeScript
Raw Normal View History

import { Controller, Get, Request, UseGuards, Header } from "@nestjs/common";
import { RateLimitGuard, RateLimit } from "@bff/core/rate-limiting/index.js";
import type { RequestWithUser } from "@bff/modules/auth/auth.types.js";
import { Public } from "@bff/modules/auth/decorators/public.decorator.js";
import {
parseInternetCatalog,
parseSimCatalog,
type InternetAddonCatalogItem,
type InternetInstallationCatalogItem,
type InternetPlanCatalogItem,
type SimActivationFeeCatalogItem,
type SimCatalogCollection,
type SimCatalogProduct,
type VpnCatalogProduct,
} from "@customer-portal/domain/services";
import { InternetCatalogService } from "./services/internet-catalog.service.js";
import { SimCatalogService } from "./services/sim-catalog.service.js";
import { VpnCatalogService } from "./services/vpn-catalog.service.js";
import { SalesforceReadThrottleGuard } from "@bff/integrations/salesforce/guards/salesforce-read-throttle.guard.js";
@Controller("services")
@Public() // Allow public access - services can be browsed without authentication
@UseGuards(SalesforceReadThrottleGuard, RateLimitGuard)
export class ServicesController {
2025-08-27 20:01:46 +09:00
constructor(
private internetCatalog: InternetCatalogService,
private simCatalog: SimCatalogService,
private vpnCatalog: VpnCatalogService
) {}
2025-08-28 16:57:57 +09:00
@Get("internet/plans")
@RateLimit({ limit: 20, ttl: 60 }) // 20 requests per minute
@Header("Cache-Control", "private, no-store") // Personalised responses: avoid browser caching (realtime invalidation relies on refetch)
async getInternetPlans(@Request() req: RequestWithUser): Promise<{
plans: InternetPlanCatalogItem[];
installations: InternetInstallationCatalogItem[];
addons: InternetAddonCatalogItem[];
}> {
2025-08-27 20:01:46 +09:00
const userId = req.user?.id;
if (!userId) {
const catalog = await this.internetCatalog.getCatalogData();
return parseInternetCatalog(catalog);
2025-08-27 20:01:46 +09:00
}
const [plans, installations, addons] = await Promise.all([
this.internetCatalog.getPlansForUser(userId),
this.internetCatalog.getInstallations(),
this.internetCatalog.getAddons(),
]);
return parseInternetCatalog({ plans, installations, addons });
2025-08-27 10:54:05 +09:00
}
2025-08-28 16:57:57 +09:00
@Get("internet/addons")
@Header("Cache-Control", "public, max-age=300, s-maxage=300") // 5 minutes
async getInternetAddons(): Promise<InternetAddonCatalogItem[]> {
2025-08-27 20:01:46 +09:00
return this.internetCatalog.getAddons();
2025-08-27 10:54:05 +09:00
}
2025-08-28 16:57:57 +09:00
@Get("internet/installations")
@Header("Cache-Control", "public, max-age=300, s-maxage=300") // 5 minutes
async getInternetInstallations(): Promise<InternetInstallationCatalogItem[]> {
2025-08-27 20:01:46 +09:00
return this.internetCatalog.getInstallations();
}
2025-08-28 16:57:57 +09:00
@Get("sim/plans")
@RateLimit({ limit: 20, ttl: 60 }) // 20 requests per minute
@Header("Cache-Control", "private, no-store") // Personalised responses: avoid browser caching (realtime invalidation relies on refetch)
async getSimCatalogData(@Request() req: RequestWithUser): Promise<SimCatalogCollection> {
2025-08-27 20:01:46 +09:00
const userId = req.user?.id;
if (!userId) {
const catalog = await this.simCatalog.getCatalogData();
return parseSimCatalog({
...catalog,
plans: catalog.plans.filter(plan => !plan.simHasFamilyDiscount),
});
2025-08-27 20:01:46 +09:00
}
const [plans, activationFees, addons] = await Promise.all([
this.simCatalog.getPlansForUser(userId),
this.simCatalog.getActivationFees(),
this.simCatalog.getAddons(),
]);
return parseSimCatalog({ plans, activationFees, addons });
2025-08-27 20:01:46 +09:00
}
2025-08-28 16:57:57 +09:00
@Get("sim/activation-fees")
@Header("Cache-Control", "public, max-age=300, s-maxage=300") // 5 minutes
async getSimActivationFees(): Promise<SimActivationFeeCatalogItem[]> {
2025-08-27 20:01:46 +09:00
return this.simCatalog.getActivationFees();
}
2025-08-28 16:57:57 +09:00
@Get("sim/addons")
@Header("Cache-Control", "public, max-age=300, s-maxage=300") // 5 minutes
async getSimAddons(): Promise<SimCatalogProduct[]> {
2025-08-27 20:01:46 +09:00
return this.simCatalog.getAddons();
}
2025-08-28 16:57:57 +09:00
@Get("vpn/plans")
@RateLimit({ limit: 20, ttl: 60 }) // 20 requests per minute
@Header("Cache-Control", "public, max-age=300, s-maxage=300") // 5 minutes
async getVpnPlans(): Promise<VpnCatalogProduct[]> {
2025-08-27 20:01:46 +09:00
return this.vpnCatalog.getPlans();
}
2025-08-28 16:57:57 +09:00
@Get("vpn/activation-fees")
@Header("Cache-Control", "public, max-age=300, s-maxage=300") // 5 minutes
async getVpnActivationFees(): Promise<VpnCatalogProduct[]> {
2025-08-27 20:01:46 +09:00
return this.vpnCatalog.getActivationFees();
2025-08-27 10:54:05 +09:00
}
2025-08-28 16:57:57 +09:00
}