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
@@ -0,0 +1,58 @@
import {
BusinessPhoneNumber,
BusinessSocialMedia,
DEFAULT_BUSINESS_SOCIAL_MEDIA,
} from './business-profile.types';
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function readString(value: unknown, fallback = '') {
return typeof value === 'string' ? value : fallback;
}
export function normalizeEmails(raw: unknown): string[] {
if (!Array.isArray(raw)) return [];
return raw
.filter((item): item is string => typeof item === 'string')
.map((item) => item.trim())
.filter(Boolean);
}
export function normalizePhoneNumbers(raw: unknown): BusinessPhoneNumber[] {
if (!Array.isArray(raw)) return [];
return raw
.filter(isRecord)
.map((item) => ({
type: (item.type === 'landline' ? 'landline' : 'cell') as BusinessPhoneNumber['type'],
number: readString(item.number).trim(),
}))
.filter((item) => item.number.length > 0);
}
export function normalizeSocialMedia(raw: unknown): BusinessSocialMedia {
const source = isRecord(raw) ? raw : {};
return {
whatsapp: readString(source.whatsapp),
telegram: readString(source.telegram),
instagram: readString(source.instagram),
linkedin: readString(source.linkedin),
youtube: readString(source.youtube),
aparat: readString(source.aparat),
};
}
export function toPrismaJsonEmails(emails: string[]) {
return emails;
}
export function toPrismaJsonPhoneNumbers(phoneNumbers: BusinessPhoneNumber[]) {
return phoneNumbers;
}
export function toPrismaJsonSocialMedia(socialMedia: BusinessSocialMedia) {
return socialMedia ?? DEFAULT_BUSINESS_SOCIAL_MEDIA;
}