Add public user-products storefront API and website docs.

Expose published customer listings under /tenants/:host/user-products (list, search, details, technical-info) and document them in the website API pack.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-10 00:19:13 +03:30
co-authored by Cursor
parent 158523df7b
commit 953b87b616
32 changed files with 3326 additions and 138 deletions
+48
View File
@@ -99,6 +99,38 @@ export class MediaService {
return { items };
}
/**
* Customer-dashboard uploads for user-product images.
* Requires business-customer membership instead of media.create.
*/
async uploadManyForCustomer(
businessIdRaw: string,
files: Express.Multer.File[],
actor: AuthUser,
) {
const businessId = BigInt(businessIdRaw);
await this.assertBusinessCustomer(businessId, actor.id);
if (!files.length) {
throw new BadRequestException('At least one file is required');
}
const business = await this.prisma.business.findUnique({
where: { id: businessId },
});
if (!business?.isActive) {
throw new NotFoundException('Business not found');
}
const items = [];
for (const file of files) {
items.push(await this.uploadOne(businessId, file, actor.id));
}
return { items };
}
async update(
businessIdRaw: string,
mediaIdRaw: string,
@@ -371,4 +403,20 @@ export class MediaService {
throw new ForbiddenException('You cannot delete media for this business');
}
}
private async assertBusinessCustomer(businessId: bigint, userId: bigint) {
if (await this.permissions.isSuperAdmin(userId)) {
return;
}
const membership = await this.prisma.businessCustomer.findUnique({
where: {
businessId_userId: { businessId, userId },
},
});
if (!membership) {
throw new ForbiddenException('You are not a customer of this business');
}
}
}