Add backend-generated sitemap with website manifest sync and nginx SEO proxy support.

Stores synced route config from /meshkee/sitemap-config.json, serves sitemap.xml and robots.txt per tenant, and invalidates cache on CMS writes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-08-22 15:15:32 +03:30
co-authored by Cursor
parent c7d5204b49
commit 2e8d7c1cfd
27 changed files with 1167 additions and 3 deletions
+2 -1
View File
@@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
import { AuthModule } from '../auth/auth.module';
import { BrandsModule } from '../brands/brands.module';
import { CategoriesModule } from '../categories/categories.module';
import { SitemapModule } from '../sitemap/sitemap.module';
import { TenantModule } from '../tenant/tenant.module';
import { ProductAiService } from './product-ai.service';
import { ProductTechnicalInfoService } from './product-technical-info.service';
@@ -10,7 +11,7 @@ import { ProductsController, PublicProductsController } from './products.control
import { ProductsService } from './products.service';
@Module({
imports: [AuthModule, BrandsModule, CategoriesModule, TenantModule],
imports: [AuthModule, BrandsModule, CategoriesModule, SitemapModule, TenantModule],
controllers: [ProductsController, PublicProductsController],
providers: [
ProductsService,
+8
View File
@@ -9,6 +9,7 @@ import { AuthUser } from '../auth/auth.types';
import { PermissionsService } from '../auth/permissions.service';
import { BrandsService } from '../brands/brands.service';
import { PrismaService } from '../prisma/prisma.service';
import { SitemapService } from '../sitemap/sitemap.service';
import { TenantService } from '../tenant/tenant.service';
import { CreateProductDto, ListProductsDto, ListPublicProductsDto, UpdateProductDto } from './dto/product.dto';
import { ProductVariationValuesService } from './product-variation-values.service';
@@ -52,6 +53,7 @@ export class ProductsService {
private readonly productVariationValues: ProductVariationValuesService,
private readonly brands: BrandsService,
private readonly tenant: TenantService,
private readonly sitemap: SitemapService,
) {}
async list(businessIdRaw: string, query: ListProductsDto, actor: AuthUser) {
@@ -276,6 +278,8 @@ export class ProductsService {
return product;
});
await this.sitemap.invalidateForBusiness(businessId);
return {
message: 'Product created successfully',
product: await this.serializeProduct(created),
@@ -414,6 +418,8 @@ export class ProductsService {
return product;
});
await this.sitemap.invalidateForBusiness(businessId);
return {
message: 'Product updated successfully',
product: await this.serializeProduct(updated),
@@ -451,6 +457,8 @@ export class ProductsService {
this.prisma.product.delete({ where: { id: productId } }),
]);
await this.sitemap.invalidateForBusiness(businessId);
return { message: 'Product deleted successfully' };
}