Kind: Service
Source: atloria-monorepo/apps/api/src/branding/branding.service.ts
Project branding — identity + colors + support email. One row per project. Everything is nullable; the frontend falls back to project name + Atloria palette when a field is blank.
BrandingService manages per-project branding settings, including identity fields, color palette values, and support email configuration. It exposes internal read/update operations and a public-safe read path, while allowing all branding fields to remain nullable so clients can fall back to the project name and default Atloria palette.
Methods
| Method | Signature | Returns | Description |
|---|---|---|---|
get | get(projectId: string, user: JwtPayload) | unknown | Get the current branding for a project. |
update | update(projectId: string, dto: UpdateBrandingDto, user: JwtPayload) | unknown | Upsert the project's branding. |
getPublic | getPublic(projectId: string) | unknown | Public read — used by the /public/p/:slugId endpoint to return branding alongside project info. |
Dependencies
PrismaServiceAuditService(optional)PlanService(optional)
Where it refuses work
BrandingServicestops the work withNotFoundExceptionwhen!project— “Project not found”.BrandingServicestops the work withForbiddenExceptionwhenproject.organizationId !== user.organizationId— “You do not have access to this project”.BrandingServicestops the work withBadRequestExceptionwhendto.primaryColor && !HEX_COLOR_REGEX.test(dto.primaryColor).BrandingServicestops the work withBadRequestExceptionwhendto.accentColor && !HEX_COLOR_REGEX.test(dto.accentColor).BrandingServicestops the work withBadRequestExceptionwhendto.supportEmail && !EMAIL_REGEX.test(dto.supportEmail).BrandingServicestops the work withBadRequestExceptionwhendto.theme && !THEME_PRESETS.includes(dto.theme as (typeof THEME_PRESETS)[number]).
When something fails
BrandingServicehandles failure in 3 places: it turns it into a return value in 2, and lets it reach the caller in 1.
Diagram
mermaidsequenceDiagram participant Client participant BrandingController participant BrandingService participant BrandingRepository participant Project Client->>BrandingController: GET /projects/:projectId/branding BrandingController->>BrandingService: get(projectId) BrandingService->>BrandingRepository: find branding for project BrandingRepository-->>BrandingService: Branding row or null BrandingService-->>BrandingController: Branding settings BrandingController-->>Client: Branding response Client->>BrandingController: PATCH /projects/:projectId/branding BrandingController->>BrandingService: update(projectId, dto) BrandingService->>BrandingRepository: create or update branding row BrandingRepository-->>BrandingService: Updated branding BrandingService-->>BrandingController: Updated settings BrandingController-->>Client: Updated branding Client->>BrandingController: GET public branding BrandingController->>BrandingService: getPublic(projectId) BrandingService->>Project: resolve public project context BrandingService-->>BrandingController: Public branding fields BrandingController-->>Client: Public branding response
Usage
tsimport { Injectable } from '@nestjs/common';
import { BrandingService } from './branding.service';
@Injectable()
export class ProjectSettingsService {
constructor(private readonly brandingService: BrandingService) {}
async updateProjectBranding(projectId: string) {
return this.brandingService.update(projectId, {
name: 'Acme Portal',
primaryColor: '#2563EB',
secondaryColor: '#0F172A',
supportEmail: 'support@acme.example',
});
}
async getPublicProjectBranding(projectId: string) {
const branding = await this.brandingService.getPublic(projectId);
return {
name: branding?.name ?? 'Project',
primaryColor: branding?.primaryColor ?? '#6366F1',
supportEmail: branding?.supportEmail ?? null,
};
}
}
AI Coding Instructions
- Keep branding scoped to a single project; there should be at most one branding record per project.
- Preserve nullable branding fields during reads and updates—do not replace missing values with defaults in persistence logic.
- Apply frontend or response-layer fallbacks for blank values using the project name and Atloria palette.
- Use
getPublic()for unauthenticated or externally visible project experiences so only public-safe branding data is exposed. - When extending branding fields, update the DTOs, persistence schema, and public response mapping consistently.
Relationships
- DEPENDS_ON →
PrismaService - DEPENDS_ON →
AuditService - DEPENDS_ON →
PlanService
Referenced By
BrandingController(DEPENDS_ON)BrandingModule(MODULE_PROVIDES)BrandingModule(MODULE_EXPORTS)DocVersionExportService(DEPENDS_ON)PublicProjectController(DEPENDS_ON)
Was this page helpful?