Add website favicon API and manual favicon profile updates.

Expose GET /tenants/{domain}/website/favicon for storefront tab icons, allow faviconMediaId on profile PATCH, and sync website API docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-26 00:51:11 +03:30
co-authored by Cursor
parent 6ce6f959ac
commit ead16080b8
13 changed files with 318 additions and 13 deletions
@@ -163,7 +163,12 @@ export class BusinessProfileService {
await this.assertLogoMedia(businessId, BigInt(dto.logoDarkMediaId));
}
if (dto.faviconMediaId !== undefined && dto.faviconMediaId !== null) {
await this.assertLogoMedia(businessId, BigInt(dto.faviconMediaId));
}
const previousFaviconMediaId = business.faviconMediaId;
const faviconExplicitlySet = dto.faviconMediaId !== undefined;
const logoChanged =
dto.logoMediaId !== undefined &&
(dto.logoMediaId === null
@@ -210,6 +215,13 @@ export class BusinessProfileService {
: { connect: { id: BigInt(dto.logoDarkMediaId) } };
}
if (dto.faviconMediaId !== undefined) {
data.faviconMedia =
dto.faviconMediaId === null
? { disconnect: true }
: { connect: { id: BigInt(dto.faviconMediaId) } };
}
if (Object.keys(data).length > 0) {
await tx.business.update({
where: { id: businessId },
@@ -234,7 +246,7 @@ export class BusinessProfileService {
}
});
if (logoChanged) {
if (logoChanged && !faviconExplicitlySet) {
if (dto.logoMediaId === null) {
await this.deleteFaviconMedia(previousFaviconMediaId);
} else if (dto.logoMediaId != null) {
@@ -115,6 +115,11 @@ export class UpdateBusinessProfileDto {
@IsInt()
logoDarkMediaId?: number | null;
@IsOptional()
@Type(() => Number)
@IsInt()
faviconMediaId?: number | null;
@IsOptional()
@IsArray()
@Type(() => Number)