Initial commit: Meshkee CMS API

NestJS backend with Prisma, Docker Compose for Postgres/Redis, and deploy docs for the production VM.
This commit is contained in:
Ali Reza
2026-07-21 17:52:36 +03:30
commit bb59d5e9ba
254 changed files with 37031 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
import { Controller, Get, Param } from '@nestjs/common';
import { TenantService } from './tenant.service';
@Controller('tenants')
export class TenantController {
constructor(private readonly tenant: TenantService) {}
/** Resolve business from website/dashboard domain (e.g. sanihome.ir). */
@Get(':host')
resolve(@Param('host') host: string) {
return this.tenant.resolvePublicBusinessByDomain(host);
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Module } from '@nestjs/common';
import { TenantController } from './tenant.controller';
import { TenantService } from './tenant.service';
@Module({
controllers: [TenantController],
providers: [TenantService],
exports: [TenantService],
})
export class TenantModule {}
+63
View File
@@ -0,0 +1,63 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { normalizeBusinessSettings } from '../business-settings/business-settings.util';
const DASHBOARD_SUBDOMAIN_PREFIXES = ['customer.', 'business.'] as const;
@Injectable()
export class TenantService {
constructor(private readonly prisma: PrismaService) {}
private normalizeTenantHost(host: string) {
const normalizedHost = host.toLowerCase().trim();
for (const prefix of DASHBOARD_SUBDOMAIN_PREFIXES) {
if (normalizedHost.startsWith(prefix)) {
return normalizedHost.slice(prefix.length);
}
}
return normalizedHost;
}
async resolveBusinessByDomain(host: string) {
const normalizedHost = this.normalizeTenantHost(host);
const domain = await this.prisma.domain.findUnique({
where: { host: normalizedHost },
include: { business: true },
});
if (!domain || !domain.business.isActive) {
throw new NotFoundException(`No business found for domain: ${host}`);
}
return domain.business;
}
async resolvePublicBusinessByDomain(host: string) {
const business = await this.resolveBusinessByDomain(host);
const normalizedHost = this.normalizeTenantHost(host);
const settings = normalizeBusinessSettings(business.settings);
const media = await this.prisma.business.findUnique({
where: { id: business.id },
select: {
logoMedia: { select: { publicUrl: true } },
faviconMedia: { select: { publicUrl: true } },
},
});
return {
id: business.id,
name: business.name,
nameFa: business.nameFa,
slug: business.slug,
domain: normalizedHost,
primaryColor: settings.branding.primaryColor,
logoUrl: media?.logoMedia?.publicUrl ?? null,
faviconUrl:
media?.faviconMedia?.publicUrl ?? media?.logoMedia?.publicUrl ?? null,
};
}
}