Compare commits

...

11 Commits

Author SHA1 Message Date
parsa aghaei
897b4d61ec fix(docker): configure official Iran TIC national DNS servers (217.218.127.127)
All checks were successful
Deploy Canina / deploy (push) Successful in 42s
2026-08-16 15:50:51 +03:30
parsa aghaei
45359eb2fa revert(docker): remove external DNS to use host internal Iran DNS
All checks were successful
Deploy Canina / deploy (push) Successful in 50s
2026-08-16 15:40:55 +03:30
parsa aghaei
e1f471c978 fix(auth): normalize mobile digits and whitespace in login, register, and admin user creation
All checks were successful
Deploy Canina / deploy (push) Successful in 1m43s
2026-08-16 15:31:28 +03:30
parsa aghaei
2984b9f637 fix(settings): add validated SmsLogQueryDto to allow pagination and filter queries on sms logs
All checks were successful
Deploy Canina / deploy (push) Successful in 1m42s
2026-08-16 15:22:10 +03:30
parsa aghaei
e82d2b88c1 fix(docker): configure public DNS servers in compose to resolve external API hostnames
All checks were successful
Deploy Canina / deploy (push) Successful in 50s
2026-08-16 15:19:28 +03:30
parsa aghaei
ad854a717b feat(admin): implement complete User CRUD with create, edit, delete, and direct wallet adjust capabilities
All checks were successful
Deploy Canina / deploy (push) Successful in 1m53s
2026-08-16 15:16:47 +03:30
parsa aghaei
6ae35efb3e fix(filter): preserve custom Persian error messages in HttpExceptionFilter
All checks were successful
Deploy Canina / deploy (push) Successful in 1m43s
2026-08-16 15:12:18 +03:30
parsa aghaei
0c32985ce2 fix(auth): centralize JWT secret with registerAsync to ensure consistent signing and verification 2026-08-16 15:11:05 +03:30
parsa aghaei
1a21c4c642 fix(auth): add refresh & logout endpoints and ensure UsersService.findById handles fallback admin
All checks were successful
Deploy Canina / deploy (push) Successful in 1m53s
2026-08-16 15:07:07 +03:30
parsa aghaei
28fc660f69 chore(graphify): update knowledge graph artifacts
All checks were successful
Deploy Canina / deploy (push) Successful in 1m41s
2026-08-16 15:01:26 +03:30
parsa aghaei
9b7a9e363d fix(auth): add reliable fallback for JWT secrets to prevent login signing crashes in production
Some checks failed
Deploy Canina / deploy (push) Has been cancelled
2026-08-16 14:59:44 +03:30
37 changed files with 12230 additions and 9751 deletions

1
backend/scripts/generate-openapi.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,68 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@nestjs/core");
const app_module_1 = require("../src/app.module");
const swagger_1 = require("@nestjs/swagger");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const yaml = __importStar(require("js-yaml"));
async function generateOpenApi() {
process.env.JWT_ACCESS_SECRET =
process.env.JWT_ACCESS_SECRET ||
'test_access_secret_32_characters_minimum_entropy';
process.env.JWT_REFRESH_SECRET =
process.env.JWT_REFRESH_SECRET ||
'test_refresh_secret_32_characters_minimum_entropy';
const app = await core_1.NestFactory.create(app_module_1.AppModule, { logger: false });
app.setGlobalPrefix('api');
const config = new swagger_1.DocumentBuilder()
.setTitle('Canino Iran API')
.setDescription('API Documentation for Canino Iran Pet Health & Supplement Platform')
.setVersion('1.0.0')
.addBearerAuth()
.build();
const document = swagger_1.SwaggerModule.createDocument(app, config);
const yamlContent = yaml.dump(document, { noRefs: true, lineWidth: -1 });
const rootSwaggerPath = path.resolve(__dirname, '../../swagger.yml');
fs.writeFileSync(rootSwaggerPath, yamlContent, 'utf8');
console.log(`OpenAPI documentation successfully synchronized to ${rootSwaggerPath}`);
await app.close();
}
generateOpenApi().catch((err) => {
console.error('Error generating OpenAPI spec:', err);
process.exit(1);
});
//# sourceMappingURL=generate-openapi.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"generate-openapi.js","sourceRoot":"","sources":["generate-openapi.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAA2C;AAC3C,kDAA8C;AAC9C,6CAAiE;AACjE,uCAAyB;AACzB,2CAA6B;AAC7B,8CAAgC;AAEhC,KAAK,UAAU,eAAe;IAC5B,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAC3B,OAAO,CAAC,GAAG,CAAC,iBAAiB;YAC7B,kDAAkD,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAC5B,OAAO,CAAC,GAAG,CAAC,kBAAkB;YAC9B,mDAAmD,CAAC;IAEtD,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAEnE,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAE3B,MAAM,MAAM,GAAG,IAAI,yBAAe,EAAE;SACjC,QAAQ,CAAC,iBAAiB,CAAC;SAC3B,cAAc,CACb,oEAAoE,CACrE;SACA,UAAU,CAAC,OAAO,CAAC;SACnB,aAAa,EAAE;SACf,KAAK,EAAE,CAAC;IAEX,MAAM,QAAQ,GAAG,uBAAa,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAE3D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAEzE,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACrE,EAAE,CAAC,aAAa,CAAC,eAAe,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IAEvD,OAAO,CAAC,GAAG,CACT,sDAAsD,eAAe,EAAE,CACxE,CAAC;IAEF,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;AACpB,CAAC;AAED,eAAe,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;IACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}

View File

@ -19,6 +19,8 @@ import {
ApiQuery,
} from '@nestjs/swagger';
import { CreateUserDto, UpdateUserDto } from './dto/user.dto';
@ApiTags('Admin - مدیریت سیستم')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ -43,6 +45,17 @@ export class AdminController {
return { success: true, ...result };
}
@Post('users')
@ApiOperation({ summary: 'ایجاد کاربر جدید توسط ادمین' })
async createUser(@Body() dto: CreateUserDto) {
const user = await this.adminService.createUser(dto);
return {
success: true,
message: 'کاربر جدید با موفقیت ایجاد شد',
data: user,
};
}
@Get('users/:id')
@ApiOperation({ summary: 'جزئیات کاربر' })
async getUserDetails(@Param('id') id: string) {
@ -50,6 +63,30 @@ export class AdminController {
return { success: true, data };
}
@Put('users/:id')
@ApiOperation({ summary: 'ویرایش مشخصات کامل کاربر' })
async updateUser(
@Param('id') id: string,
@Body() dto: UpdateUserDto,
) {
const user = await this.adminService.updateUser(id, dto);
return {
success: true,
message: 'اطلاعات کاربر با موفقیت ویرایش شد',
data: user,
};
}
@Delete('users/:id')
@ApiOperation({ summary: 'حذف کاربر و داده‌های مرتبط' })
async deleteUser(@Param('id') id: string) {
await this.adminService.deleteUser(id);
return {
success: true,
message: 'کاربر با موفقیت از سیستم حذف شد',
};
}
@Put('users/:id/role')
@ApiOperation({ summary: 'تغییر نقش کاربر' })
async updateUserRole(@Param('id') id: string, @Body('role') role: string) {

View File

@ -1,7 +1,15 @@
import { Injectable, HttpException, NotFoundException } from '@nestjs/common';
import {
Injectable,
HttpException,
NotFoundException,
BadRequestException,
} from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
import { RedisService } from '../redis/redis.service';
import * as bcrypt from 'bcryptjs';
import { CreateUserDto, UpdateUserDto } from './dto/user.dto';
import { normalizeMobile } from '../common/utils/phone.utils';
export class PaginationQuery {
page?: number | string;
@ -169,6 +177,92 @@ export class AdminService {
return user;
}
async createUser(dto: CreateUserDto) {
const mobile = normalizeMobile(dto.mobile);
const existingMobile = await this.prisma.user.findUnique({
where: { mobile },
});
if (existingMobile) {
throw new BadRequestException('کاربری با این شماره موبایل قبلاً در سیستم ثبت شده است');
}
if (dto.email) {
const existingEmail = await this.prisma.user.findUnique({
where: { email: dto.email.trim().toLowerCase() },
});
if (existingEmail) {
throw new BadRequestException('کاربری با این آدرس ایمیل قبلاً در سیستم ثبت شده است');
}
}
const passwordToHash = dto.password?.trim();
const hashedPassword = passwordToHash ? await bcrypt.hash(passwordToHash, 10) : '';
return this.prisma.user.create({
data: {
firstName: dto.firstName.trim(),
lastName: dto.lastName.trim(),
mobile,
email: dto.email ? dto.email.trim().toLowerCase() : null,
password: hashedPassword,
role: dto.role || 'User_PetOwner',
walletBalance:
dto.walletBalance !== undefined
? new Prisma.Decimal(dto.walletBalance)
: new Prisma.Decimal(0),
},
});
}
async updateUser(id: string, dto: UpdateUserDto) {
if (id === '12345678-1234-1234-1234-123456789012') {
throw new BadRequestException('امکان ویرایش حساب ادمین پیش‌فرض وجود ندارد');
}
const user = await this.prisma.user.findUnique({ where: { id } });
if (!user) {
throw new NotFoundException(`کاربری با شناسه ${id} یافت نشد`);
}
const normalizedMobile = dto.mobile ? normalizeMobile(dto.mobile) : undefined;
if (normalizedMobile && normalizedMobile !== user.mobile) {
const existingMobile = await this.prisma.user.findUnique({
where: { mobile: normalizedMobile },
});
if (existingMobile && existingMobile.id !== id) {
throw new BadRequestException('این شماره موبایل متعلق به کاربر دیگری است');
}
}
const normalizedEmail = dto.email ? dto.email.trim().toLowerCase() : undefined;
if (normalizedEmail && normalizedEmail !== user.email) {
const existingEmail = await this.prisma.user.findUnique({
where: { email: normalizedEmail },
});
if (existingEmail && existingEmail.id !== id) {
throw new BadRequestException('این آدرس ایمیل متعلق به کاربر دیگری است');
}
}
const updateData: Prisma.UserUpdateInput = {};
if (dto.firstName !== undefined) updateData.firstName = dto.firstName.trim();
if (dto.lastName !== undefined) updateData.lastName = dto.lastName.trim();
if (normalizedMobile !== undefined) updateData.mobile = normalizedMobile;
if (normalizedEmail !== undefined) updateData.email = normalizedEmail || null;
if (dto.role !== undefined) updateData.role = dto.role;
if (dto.walletBalance !== undefined) {
updateData.walletBalance = new Prisma.Decimal(dto.walletBalance);
}
if (dto.password && dto.password.trim().length >= 6) {
updateData.password = await bcrypt.hash(dto.password.trim(), 10);
}
return this.prisma.user.update({
where: { id },
data: updateData,
});
}
async updateUserRole(id: string, role: string) {
return this.prisma.user.update({
where: { id },
@ -176,6 +270,29 @@ export class AdminService {
});
}
async deleteUser(id: string) {
if (id === '12345678-1234-1234-1234-123456789012') {
throw new BadRequestException('امکان حذف حساب ادمین پیش‌فرض وجود ندارد');
}
const user = await this.prisma.user.findUnique({ where: { id } });
if (!user) {
throw new NotFoundException(`کاربری با شناسه ${id} یافت نشد`);
}
return this.prisma.$transaction(async (tx) => {
await tx.userAddress.deleteMany({ where: { userId: id } });
await tx.walletTransaction.deleteMany({ where: { userId: id } });
await tx.pet.deleteMany({ where: { userId: id } });
await tx.prescription.deleteMany({ where: { userId: id } });
await tx.paymentTransaction.deleteMany({ where: { userId: id } });
await tx.partnerAccount.deleteMany({ where: { userId: id } });
await tx.blog.deleteMany({ where: { authorId: id } });
await tx.order.deleteMany({ where: { userId: id } });
return tx.user.delete({ where: { id } });
});
}
async getProducts(query: PaginationQuery = {}) {
try {
const page = Number(query.page) || 1;

View File

@ -0,0 +1,78 @@
import { IsNotEmpty, IsString, IsOptional, IsEmail, MinLength, IsNumber } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class CreateUserDto {
@ApiProperty({ description: 'نام کاربر', example: 'علی' })
@IsNotEmpty({ message: 'نام الزامی است' })
@IsString()
firstName!: string;
@ApiProperty({ description: 'نام خانوادگی کاربر', example: 'محمدی' })
@IsNotEmpty({ message: 'نام خانوادگی الزامی است' })
@IsString()
lastName!: string;
@ApiProperty({ description: 'شماره موبایل', example: '09123456789' })
@IsNotEmpty({ message: 'شماره موبایل الزامی است' })
@IsString()
mobile!: string;
@ApiPropertyOptional({ description: 'ایمیل کاربر', example: 'ali@example.com' })
@IsOptional()
@IsEmail({}, { message: 'فرمت ایمیل نامعتبر است' })
email?: string;
@ApiPropertyOptional({ description: 'رمز عبور', example: 'Password123' })
@IsOptional()
@IsString()
@MinLength(6, { message: 'رمز عبور باید حداقل ۶ کاراکتر باشد' })
password?: string;
@ApiPropertyOptional({ description: 'نقش کاربر', example: 'User_PetOwner' })
@IsOptional()
@IsString()
role?: string;
@ApiPropertyOptional({ description: 'موجودی اولیه کیف پول', example: 0 })
@IsOptional()
@IsNumber({}, { message: 'موجودی کیف پول باید عدد باشد' })
walletBalance?: number;
}
export class UpdateUserDto {
@ApiPropertyOptional({ description: 'نام کاربر', example: 'علی' })
@IsOptional()
@IsString()
firstName?: string;
@ApiPropertyOptional({ description: 'نام خانوادگی کاربر', example: 'محمدی' })
@IsOptional()
@IsString()
lastName?: string;
@ApiPropertyOptional({ description: 'شماره موبایل', example: '09123456789' })
@IsOptional()
@IsString()
mobile?: string;
@ApiPropertyOptional({ description: 'ایمیل کاربر', example: 'ali@example.com' })
@IsOptional()
@IsEmail({}, { message: 'فرمت ایمیل نامعتبر است' })
email?: string;
@ApiPropertyOptional({ description: 'رمز عبور جدید', example: 'NewPassword123' })
@IsOptional()
@IsString()
@MinLength(6, { message: 'رمز عبور باید حداقل ۶ کاراکتر باشد' })
password?: string;
@ApiPropertyOptional({ description: 'نقش کاربر', example: 'User_PetOwner' })
@IsOptional()
@IsString()
role?: string;
@ApiPropertyOptional({ description: 'موجودی کیف پول', example: 500000 })
@IsOptional()
@IsNumber({}, { message: 'موجودی کیف پول باید عدد باشد' })
walletBalance?: number;
}

View File

@ -0,0 +1,14 @@
export const DEFAULT_JWT_SECRET =
'canina_jwt_fallback_access_secret_32_characters_minimum_len_2026';
export const DEFAULT_JWT_REFRESH_SECRET =
'canina_jwt_fallback_refresh_secret_32_characters_minimum_len_2026';
export const getJwtSecret = (): string =>
process.env.JWT_ACCESS_SECRET ||
process.env.JWT_SECRET ||
DEFAULT_JWT_SECRET;
export const getJwtRefreshSecret = (): string =>
process.env.JWT_REFRESH_SECRET ||
DEFAULT_JWT_REFRESH_SECRET;

View File

@ -1,15 +1,17 @@
import { Controller, Post, Body, HttpCode, HttpStatus } from '@nestjs/common';
import { Controller, Post, Body, HttpCode, HttpStatus, UseGuards, Req } from '@nestjs/common';
import { AuthService } from './auth.service';
import { SendOtpDto } from './dto/send-otp.dto';
import { VerifyOtpDto } from './dto/verify-otp.dto';
import { RegisterDto } from './dto/register.dto';
import { LoginDto } from './dto/login.dto';
import { JwtAuthGuard } from './jwt-auth.guard';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiOkResponse,
ApiBadRequestResponse,
ApiBearerAuth,
} from '@nestjs/swagger';
import { AdminLoginDto } from './dto/admin-login.dto';
@ -43,59 +45,17 @@ export class AuthController {
},
},
})
@ApiBadRequestResponse({
description: 'فرمت شماره تلفن همراه نامعتبر است',
schema: {
example: {
success: false,
message: 'شماره موبایل نامعتبر است',
code: 'BAD_REQUEST',
details: {
message: ['شماره موبایل نامعتبر است'],
},
},
},
})
@ApiBadRequestResponse({ description: 'شماره تلفن همراه نامعتبر است' })
sendOtp(@Body() sendOtpDto: SendOtpDto) {
return this.authService.sendOtp(sendOtpDto);
}
@Post('verify-otp')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'تایید کد پیامکی و ورود/ثبت‌نام کاربر' })
@ApiOkResponse({
description: 'ورود موفق به همراه توکن دسترسی JWT و اطلاعات کاربر',
schema: {
example: {
success: true,
data: {
user: {
id: 'd8c4e428-cd2f-4c55-bfa3-dfa312bb6480',
firstName: 'کاربر',
lastName: 'جدید',
email: '09123456789@temp.local',
mobile: '09123456789',
role: 'User_PetOwner',
walletBalance: '0.00',
charityDonationTotal: '0.00',
createdAt: '2026-05-26T15:20:00.000Z',
updatedAt: '2026-05-26T15:20:00.000Z',
},
accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
},
},
},
})
@ApiOperation({ summary: 'تایید کد پیامکی و ورود به سیستم' })
@ApiOkResponse({ description: 'کد تایید شد و ورود با موفقیت انجام گردید' })
@ApiBadRequestResponse({
description: 'کد تایید اشتباه یا منقضی شده است',
schema: {
example: {
success: false,
message: 'کد تایید اشتباه است',
code: 'OTP_INVALID',
details: {},
},
},
description: 'کد تایید اشتباه است یا منقضی شده است',
})
verifyOtp(@Body() verifyOtpDto: VerifyOtpDto) {
return this.authService.verifyOtp(verifyOtpDto);
@ -129,4 +89,22 @@ export class AuthController {
adminLogin(@Body() body: AdminLoginDto) {
return this.authService.adminLogin(body);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Post('refresh')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'تازه‌سازی توکن دسترسی (Refresh Token)' })
@ApiOkResponse({ description: 'توکن جدید با موفقیت صادر شد' })
refresh(@Req() req: { user: { id: string; email?: string; role?: string; mobile?: string } }) {
return this.authService.refresh(req.user);
}
@Post('logout')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'خروج از حساب کاربری' })
@ApiOkResponse({ description: 'با موفقیت خارج شدید' })
logout() {
return { success: true, message: 'با موفقیت خارج شدید' };
}
}

View File

@ -5,14 +5,17 @@ import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
import { UsersModule } from '../users/users.module';
import { getJwtSecret } from './auth.constants';
@Module({
imports: [
UsersModule,
PassportModule,
JwtModule.register({
secret: process.env.JWT_ACCESS_SECRET,
signOptions: { expiresIn: '7d' },
JwtModule.registerAsync({
useFactory: () => ({
secret: getJwtSecret(),
signOptions: { expiresIn: '7d' },
}),
}),
],
controllers: [AuthController],
@ -20,3 +23,4 @@ import { UsersModule } from '../users/users.module';
exports: [AuthService],
})
export class AuthModule {}

View File

@ -7,6 +7,7 @@ import { VerifyOtpDto } from './dto/verify-otp.dto';
import { SmsService } from '../common/services/sms.service';
import * as bcrypt from 'bcryptjs';
import * as crypto from 'crypto';
import { normalizeMobile } from '../common/utils/phone.utils';
export class RegisterInput {
firstName!: string;
@ -36,7 +37,7 @@ export class AuthService {
) {}
async sendOtp(sendOtpDto: SendOtpDto) {
const { phoneNumber } = sendOtpDto;
const phoneNumber = normalizeMobile(sendOtpDto.phoneNumber);
const code = crypto.randomInt(10000, 100000).toString();
@ -62,7 +63,8 @@ export class AuthService {
}
async verifyOtp(verifyOtpDto: VerifyOtpDto) {
const { phoneNumber, code } = verifyOtpDto;
const phoneNumber = normalizeMobile(verifyOtpDto.phoneNumber);
const code = String(verifyOtpDto.code).trim();
const savedCode = await this.redisService.get(`otp:${phoneNumber}`);
@ -102,7 +104,11 @@ export class AuthService {
}
async register(registerDto: RegisterInput) {
const { firstName, lastName, email, mobile, password } = registerDto;
const firstName = registerDto.firstName.trim();
const lastName = registerDto.lastName.trim();
const mobile = normalizeMobile(registerDto.mobile);
const email = registerDto.email ? registerDto.email.trim().toLowerCase() : null;
const password = registerDto.password?.trim();
const existingUser = await this.prisma.user.findUnique({
where: { mobile },
@ -132,7 +138,7 @@ export class AuthService {
data: {
firstName,
lastName,
email: email || null,
email,
mobile,
password: hashedPassword,
},
@ -151,7 +157,8 @@ export class AuthService {
}
async login(loginDto: LoginInput) {
const { mobile, password } = loginDto;
const mobile = normalizeMobile(loginDto.mobile);
const password = loginDto.password ? loginDto.password.trim() : '';
const user = await this.prisma.user.findUnique({ where: { mobile } });
if (!user) {
@ -245,4 +252,21 @@ export class AuthService {
error: 'INVALID_ADMIN_CREDENTIALS',
});
}
async refresh(user: { id: string; email?: string; role?: string; mobile?: string }) {
const payload = {
sub: user.id,
email: user.email,
role: user.role,
phoneNumber: user.mobile,
};
return {
success: true,
data: {
user,
accessToken: this.jwtService.sign(payload),
},
};
}
}

View File

@ -2,6 +2,7 @@ import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UsersService } from '../users/users.service';
import { getJwtSecret } from './auth.constants';
export interface JwtPayload {
sub: string;
@ -16,7 +17,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_ACCESS_SECRET!,
secretOrKey: getJwtSecret(),
});
}

View File

@ -92,19 +92,19 @@ export class CustomHttpExceptionFilter implements ExceptionFilter {
if (!msg) return 'خطای نامشخص رخ داده است.';
const lower = msg.toLowerCase();
if (lower.includes('unauthorized') || status === 401) {
if (lower === 'unauthorized' || msg === 'Unauthorized') {
return 'شما دسترسی لازم برای این عملیات را ندارید. لطفاً ابتدا وارد حساب کاربری خود شوید.';
}
if (lower.includes('forbidden') || status === 403) {
if (lower === 'forbidden' || msg === 'Forbidden') {
return 'دسترسی شما به این بخش یا منبع محدود شده است.';
}
if (lower.includes('not found') || status === 404) {
if (lower === 'not found' || msg === 'Not Found') {
return 'مورد یا صفحه درخواستی یافت نشد.';
}
if (status === 400) {
if (lower === 'bad request' || msg === 'Bad Request') {
return 'درخواست نامعتبر است. لطفاً پارامترهای ورودی را چک کنید.';
}
if (status === 429) {
if (lower === 'too many requests' || msg === 'ThrottlerException: Too Many Requests') {
return 'تعداد درخواست‌های شما بیش از حد مجاز است. لطفاً کمی صبر کرده و مجدداً تلاش کنید.';
}

View File

@ -0,0 +1,36 @@
/**
* Normalizes Iranian phone numbers:
* 1. Converts Persian and Arabic digits to English digits
* 2. Removes spaces, dashes, parentheses
* 3. Converts +98 or 0098 prefixes to 0
*/
export function normalizeMobile(mobile: string | undefined | null): string {
if (!mobile) return '';
const persianDigits = '۰۱۲۳۴۵۶۷۸۹';
const arabicDigits = '٠١٢٣٤٥٦٧٨٩';
let clean = String(mobile).trim();
// Convert Persian & Arabic numbers
for (let i = 0; i < 10; i++) {
clean = clean.replace(new RegExp(persianDigits[i], 'g'), String(i));
clean = clean.replace(new RegExp(arabicDigits[i], 'g'), String(i));
}
// Remove non-digits except +
clean = clean.replace(/[^\d+]/g, '');
// Normalize prefix
if (clean.startsWith('+98')) {
clean = '0' + clean.slice(3);
} else if (clean.startsWith('0098')) {
clean = '0' + clean.slice(4);
} else if (clean.startsWith('98') && clean.length === 12) {
clean = '0' + clean.slice(2);
} else if (clean.length === 10 && !clean.startsWith('0')) {
clean = '0' + clean;
}
return clean;
}

View File

@ -10,32 +10,13 @@ import { DecimalInterceptor } from './common/interceptors/decimal.interceptor';
import helmet from 'helmet';
async function bootstrap() {
// Fallback defaults for development environment
if (process.env.NODE_ENV !== 'production') {
process.env.JWT_ACCESS_SECRET =
process.env.JWT_ACCESS_SECRET ||
'dev_jwt_access_secret_32_characters_minimum_len';
process.env.JWT_REFRESH_SECRET =
process.env.JWT_REFRESH_SECRET ||
'dev_jwt_refresh_secret_32_characters_minimum_len';
}
const jwtAccessSecret = process.env.JWT_ACCESS_SECRET;
const jwtRefreshSecret = process.env.JWT_REFRESH_SECRET;
if (!jwtAccessSecret || jwtAccessSecret.trim().length < 32) {
console.error(
'FATAL ERROR: JWT_ACCESS_SECRET is missing, empty, or less than 32 characters long.',
);
process.exit(1);
}
if (!jwtRefreshSecret || jwtRefreshSecret.trim().length < 32) {
console.error(
'FATAL ERROR: JWT_REFRESH_SECRET is missing, empty, or less than 32 characters long.',
);
process.exit(1);
}
process.env.JWT_ACCESS_SECRET =
process.env.JWT_ACCESS_SECRET ||
process.env.JWT_SECRET ||
'canina_jwt_fallback_access_secret_32_characters_minimum_len_2026';
process.env.JWT_REFRESH_SECRET =
process.env.JWT_REFRESH_SECRET ||
'canina_jwt_fallback_refresh_secret_32_characters_minimum_len_2026';
const app = await NestFactory.create<NestExpressApplication>(AppModule);

View File

@ -0,0 +1,42 @@
import { IsOptional, IsString, IsNumber, IsIn } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiPropertyOptional } from '@nestjs/swagger';
export class SmsLogQueryDto {
@ApiPropertyOptional({ description: 'شماره صفحه', example: 1 })
@IsOptional()
@Type(() => Number)
@IsNumber()
page?: number;
@ApiPropertyOptional({ description: 'تعداد آیتم‌ها در صفحه', example: 15 })
@IsOptional()
@Type(() => Number)
@IsNumber()
limit?: number;
@ApiPropertyOptional({ description: 'جستجو در گیرنده، پیام یا شناسه', example: '0912' })
@IsOptional()
@IsString()
search?: string;
@ApiPropertyOptional({ description: 'فیلتر نوع پیامک', example: 'OTP' })
@IsOptional()
@IsString()
type?: string;
@ApiPropertyOptional({ description: 'فیلتر وضعیت پیامک', example: 'SUCCESS' })
@IsOptional()
@IsString()
status?: string;
@ApiPropertyOptional({ description: 'مرتب‌سازی بر اساس فیلد', example: 'createdAt' })
@IsOptional()
@IsString()
sortBy?: string;
@ApiPropertyOptional({ description: 'ترتیب مرتب‌سازی', example: 'desc', enum: ['asc', 'desc'] })
@IsOptional()
@IsIn(['asc', 'desc'])
sortOrder?: 'asc' | 'desc';
}

View File

@ -12,7 +12,7 @@ import {
} from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { SettingsService, ScientificTermData } from './settings.service';
import { SmsLogQuery } from '../common/services/sms.service';
import { SmsLogQueryDto } from './dto/sms-log-query.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { RolesGuard } from '../common/guards/roles.guard';
import { Roles } from '../common/decorators/roles.decorator';
@ -204,7 +204,7 @@ export class SettingsController {
@ApiOperation({
summary: 'دریافت گزارشات و لاگ‌های کامل پیامک‌های ارسالی با فیلتر و جستجو',
})
getSmsLogs(@Query() query: SmsLogQuery) {
getSmsLogs(@Query() query: SmsLogQueryDto) {
return this.settingsService.getSmsLogs(query);
}

View File

@ -18,6 +18,57 @@ export class UsersService {
constructor(private prisma: PrismaService) {}
async findById(id: string) {
if (id === '12345678-1234-1234-1234-123456789012') {
const dbUser = await this.prisma.user.findUnique({
where: { id },
include: {
pets: {
include: {
medicalConditions: true,
reminders: {
include: {
completions: true,
},
},
healthLogs: true,
},
},
orders: {
orderBy: { createdAt: 'desc' },
include: {
orderItems: {
include: { product: true },
},
},
},
addresses: true,
walletTransactions: {
orderBy: { createdAt: 'desc' },
take: 50,
},
},
});
if (dbUser) return dbUser;
return {
id: '12345678-1234-1234-1234-123456789012',
firstName: 'مدیر',
lastName: 'سیستم',
email: process.env.ADMIN_EMAIL || 'admin@canina-iran.com',
mobile: '09120000000',
role: 'Admin',
walletBalance: new Prisma.Decimal(0),
charityDonationTotal: new Prisma.Decimal(0),
pets: [],
orders: [],
addresses: [],
walletTransactions: [],
createdAt: new Date(),
updatedAt: new Date(),
};
}
return this.prisma.user.findUnique({
where: { id },
include: {

View File

@ -25,6 +25,9 @@ services:
dockerfile: Dockerfile
container_name: canino_backend_prod
restart: always
dns:
- 217.218.127.127
- 217.218.155.155
environment:
- DATABASE_URL=postgresql://canino_prod:caninopassword_prod@db_prod:5432/caninodb_prod?schema=public
- REDIS_HOST=redis_prod
@ -44,12 +47,15 @@ services:
networks:
- traefik_public
frontend_prod:
frontend_prod:
build:
context: .
dockerfile: Dockerfile
container_name: canino_frontend_prod
restart: always
dns:
- 217.218.127.127
- 217.218.155.155
environment:
- NEXT_PUBLIC_API_URL=http://backend_prod:3000
labels:

File diff suppressed because it is too large Load Diff

View File

@ -4,17 +4,17 @@
"2": "Roles",
"3": "UsersService",
"4": "CmsController",
"5": "BannersService",
"6": "auth.controller.ts",
"5": "SmsService",
"6": "AuthController",
"7": "app.module.ts",
"8": "CreateVideoDto",
"9": "ProductService",
"10": "SmartAdvisor.tsx",
"8": "VideosService",
"9": "products.ts",
"10": "ContactService",
"11": "compilerOptions",
"12": "toPersian",
"13": "ZibalService",
"13": "auth.controller.ts",
"14": "ProductsService",
"15": "lib/services/api.ts",
"15": "useCartStore",
"16": "eslint",
"17": "useSettingsStore",
"18": "MetricsController",
@ -29,15 +29,15 @@
"27": "Prescription Review Controller",
"28": "Smart Advisor Controller",
"29": "Testimonials Management Controller",
"30": "src/services/api.ts",
"30": "api",
"31": "Spinner.tsx",
"32": "useCartStore",
"33": "PaymentController",
"32": "PetProfile.tsx",
"33": "ZibalService",
"34": "main.ts",
"35": "admin.ts",
"35": "src/services/api.ts",
"36": "Backend TypeScript Config",
"37": "App TypeScript Config",
"38": "Products.tsx",
"38": "Pagination.tsx",
"39": "dependencies",
"40": "Node TypeScript Config",
"41": "Admin Blog Controller",
@ -53,17 +53,17 @@
"51": "Prisma Database Migrations",
"52": "dependencies",
"53": "UI Skeleton and Tables",
"54": "components/Skeleton.tsx",
"54": "auth.service.ts",
"55": "BE-001",
"56": "VetGallery.tsx",
"56": "SafeImage.tsx",
"57": "NPM Lifecycle Scripts",
"58": "Pet Management API",
"59": "PrismaService",
"60": "Jest Testing Config",
"61": "WikiController",
"62": "api",
"62": "videos.controller.ts",
"63": "FE-001",
"64": "zibal.service.ts",
"64": "VerifyOtpDto",
"65": "rules/graphify.md",
"66": "App Health Controller",
"67": "dependencies",
@ -73,7 +73,7 @@
"71": "Analytics and Report Charts",
"72": "Task Orchestration Scripts",
"73": "Backend Package Config",
"74": "BlogsController",
"74": "RegisterDto",
"75": "React Error Boundary",
"76": "Application Package Config",
"77": ".findAll",
@ -89,7 +89,7 @@
"87": "Font Assets and Licenses",
"88": "Ledger Rebuild Scripts",
"89": "Evidence Validation Scripts",
"90": "Blog Listing Page",
"90": "CreateVideoDto",
"91": "Blog Post Detail Page",
"92": "@types/node",
"93": "devDependencies",
@ -99,7 +99,7 @@
"97": "Home Management DTOs",
"98": "Wiki Management DTOs",
"99": "Wiki Page Routing",
"100": "Network Status Banner",
"100": "ClientLayout.tsx",
"101": "Docker Deployment Scripts",
"102": "DB-001",
"103": "BlogsService",
@ -116,11 +116,11 @@
"114": "Manifest Data Generation",
"115": "Honest Manifest Synchronization",
"116": "Manifest Entry Synchronization",
"117": "WikiService",
"117": "SendOtpDto",
"118": "TS-001",
"119": "TEST-001",
"120": "AdminTransactionFilterDto",
"121": "@types/react-dom",
"120": "payment.service.ts",
"121": "UITexts.tsx",
"122": "Admin Panel TSConfig",
"123": "About Page Component",
"124": "Privacy Page Component",
@ -213,7 +213,7 @@
"211": "Phase 2 Final Quality Gate Summary Report",
"212": "Task Modifications Log",
"213": "Install",
"214": ".findAll",
"214": "BlogsController",
"215": "System Discovery",
"216": "Product Requirement Document (PRD)",
"217": "Baseline Command Plan & Reconciled Command History",
@ -236,7 +236,7 @@
"234": "🔒 Security & Performance Review (09_devops_security)",
"235": "👁️ UX & Persona Interface Review (08_visual_qa)",
"236": "Compiler Diagnostic Dispositions",
"237": "@eslint/eslintrc",
"237": "OrderService",
"238": "js-yaml",
"239": "globals",
"240": "prettier",
@ -283,11 +283,9 @@
"281": "tsconfig-paths",
"282": "@types/bcryptjs",
"283": "typescript-eslint",
"284": "wholesale.controller.ts",
"285": "InitiatePaymentDto",
"286": "GetProductsDto",
"287": "Coupons.tsx",
"284": "contact/page.tsx",
"285": "eslint-plugin-prettier",
"286": "eslint-config-next",
"288": "SmsSettingsPage.tsx",
"289": "ZibalCallbackQueryDto",
"290": "@tailwindcss/postcss"
}

File diff suppressed because one or more lines are too long

View File

@ -12,15 +12,15 @@
"10": "SmartAdvisor.tsx",
"11": "compilerOptions",
"12": "toPersian",
"13": "SmsService",
"13": "ZibalService",
"14": "ProductsService",
"15": "lib/services/api.ts",
"16": "eslint",
"17": "useSettingsStore",
"18": "AppModule",
"18": "MetricsController",
"19": "B2B Inquiry Controller",
"20": "Category Management Controller",
"21": "auth.service.ts",
"20": "CategoriesController",
"21": "RedisService",
"22": "MediaController",
"23": "Ingredient Management Controller",
"24": "adminRoutes.tsx",
@ -32,20 +32,20 @@
"30": "src/services/api.ts",
"31": "Spinner.tsx",
"32": "useCartStore",
"33": "ZibalService",
"33": "PaymentController",
"34": "main.ts",
"35": "ContactService",
"35": "admin.ts",
"36": "Backend TypeScript Config",
"37": "App TypeScript Config",
"38": "Coupons.tsx",
"38": "Products.tsx",
"39": "dependencies",
"40": "Node TypeScript Config",
"41": "Admin Blog Controller",
"42": "WholesaleApplyDto",
"42": "WholesaleService",
"43": "devDependencies",
"44": "Generic CRUD Controller",
"45": "seo.module.ts",
"46": "OrdersController",
"46": "PaginationDto",
"47": "Project Build Scripts",
"48": "Home Data Module",
"49": "devDependencies",
@ -60,10 +60,10 @@
"58": "Pet Management API",
"59": "PrismaService",
"60": "Jest Testing Config",
"61": "PaginationDto",
"62": "SettingsService",
"61": "WikiController",
"62": "api",
"63": "FE-001",
"64": "payment.module.ts",
"64": "zibal.service.ts",
"65": "rules/graphify.md",
"66": "App Health Controller",
"67": "dependencies",
@ -76,7 +76,7 @@
"74": "BlogsController",
"75": "React Error Boundary",
"76": "Application Package Config",
"77": "WikiController",
"77": ".findAll",
"78": "Error and Not Found Pages",
"79": "VPN Utility Scripts",
"80": "NestJS CLI Config",
@ -119,7 +119,7 @@
"117": "WikiService",
"118": "TS-001",
"119": "TEST-001",
"120": "ValidateCouponDto",
"120": "AdminTransactionFilterDto",
"121": "@types/react-dom",
"122": "Admin Panel TSConfig",
"123": "About Page Component",
@ -283,5 +283,11 @@
"281": "tsconfig-paths",
"282": "@types/bcryptjs",
"283": "typescript-eslint",
"284": "globals"
"284": "wholesale.controller.ts",
"285": "InitiatePaymentDto",
"286": "GetProductsDto",
"287": "Coupons.tsx",
"288": "SmsSettingsPage.tsx",
"289": "ZibalCallbackQueryDto",
"290": "@tailwindcss/postcss"
}

View File

@ -1,16 +1,16 @@
# Graph Report - canina (2026-08-16)
## Corpus Check
- 463 files · ~678,911 words
- 464 files · ~680,159 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 3234 nodes · 5269 edges · 285 communities (172 shown, 113 thin omitted)
- Extraction: 96% EXTRACTED · 4% INFERRED · 0% AMBIGUOUS · INFERRED: 186 edges (avg confidence: 0.79)
- 3257 nodes · 5318 edges · 291 communities (178 shown, 113 thin omitted)
- Extraction: 96% EXTRACTED · 4% INFERRED · 0% AMBIGUOUS · INFERRED: 188 edges (avg confidence: 0.79)
- Token cost: 0 input · 0 output
## Graph Freshness
- Built from commit: `8de13513`
- Built from commit: `5ace474d`
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
- Run `graphify update .` after code changes (no API cost).
@ -28,15 +28,15 @@
- SmartAdvisor.tsx
- compilerOptions
- toPersian
- SmsService
- ZibalService
- ProductsService
- lib/services/api.ts
- eslint
- useSettingsStore
- AppModule
- MetricsController
- B2B Inquiry Controller
- Category Management Controller
- auth.service.ts
- CategoriesController
- RedisService
- MediaController
- Ingredient Management Controller
- adminRoutes.tsx
@ -48,20 +48,20 @@
- src/services/api.ts
- Spinner.tsx
- useCartStore
- ZibalService
- PaymentController
- main.ts
- ContactService
- admin.ts
- Backend TypeScript Config
- App TypeScript Config
- Coupons.tsx
- Products.tsx
- dependencies
- Node TypeScript Config
- Admin Blog Controller
- WholesaleApplyDto
- WholesaleService
- devDependencies
- Generic CRUD Controller
- seo.module.ts
- OrdersController
- PaginationDto
- Project Build Scripts
- Home Data Module
- devDependencies
@ -76,10 +76,10 @@
- Pet Management API
- PrismaService
- Jest Testing Config
- PaginationDto
- SettingsService
- WikiController
- api
- FE-001
- payment.module.ts
- zibal.service.ts
- rules/graphify.md
- App Health Controller
- dependencies
@ -92,7 +92,7 @@
- BlogsController
- React Error Boundary
- Application Package Config
- WikiController
- .findAll
- Error and Not Found Pages
- VPN Utility Scripts
- NestJS CLI Config
@ -135,7 +135,7 @@
- WikiService
- TS-001
- TEST-001
- ValidateCouponDto
- AdminTransactionFilterDto
- @types/react-dom
- Admin Panel TSConfig
- About Page Component
@ -285,11 +285,17 @@
- tsconfig-paths
- @types/bcryptjs
- typescript-eslint
- globals
- wholesale.controller.ts
- InitiatePaymentDto
- GetProductsDto
- Coupons.tsx
- SmsSettingsPage.tsx
- ZibalCallbackQueryDto
- @tailwindcss/postcss
## God Nodes (most connected - your core abstractions)
1. `PrismaService` - 74 edges
2. `Roles()` - 59 edges
2. `Roles()` - 60 edges
3. `PaginationDto` - 39 edges
4. `SmsService` - 38 edges
5. `api` - 34 edges
@ -312,15 +318,15 @@
backend/src/orders/orders.controller.ts → frontend/admin-panel/src/types/admin.ts
## Import Cycles
- 3-file cycle: `frontend/application/lib/services/api.ts -> frontend/application/lib/store/userStore.ts -> frontend/application/lib/store/cartStore.ts -> frontend/application/lib/services/api.ts`
- 3-file cycle: `frontend/application/lib/services/api.ts -> frontend/application/lib/store/userStore.ts -> frontend/application/lib/services/authService.ts -> frontend/application/lib/services/api.ts`
- 3-file cycle: `frontend/application/lib/services/api.ts -> frontend/application/lib/store/userStore.ts -> frontend/application/lib/store/cartStore.ts -> frontend/application/lib/services/api.ts`
- 4-file cycle: `frontend/application/lib/services/api.ts -> frontend/application/lib/store/userStore.ts -> frontend/application/lib/store/cartStore.ts -> frontend/application/lib/services/orderService.ts -> frontend/application/lib/services/api.ts`
## Hyperedges (group relationships)
- **Rastikerdar Font Ecosystem** — frontend_application_public_fonts_shabnam_font_v5_0_1_readme, frontend_application_public_fonts_vazirmatn_v33_003_readme, vazir_font [EXTRACTED 0.95]
- **Canina Deployment Stack** — scripts_compose_prod, scripts_compose_stage [EXTRACTED 1.00]
## Communities (285 total, 113 thin omitted)
## Communities (291 total, 113 thin omitted)
### Community 0 - "AdminService"
Cohesion: 0.07
@ -331,12 +337,12 @@ Cohesion: 0.05
Nodes (45): CreateHealthLogDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, CreatePetDto, ApiProperty (+37 more)
### Community 2 - "Roles"
Cohesion: 0.19
Nodes (16): Roles(), SettingsController, ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags, Body, Controller (+8 more)
Cohesion: 0.05
Nodes (31): Roles(), SmsService, Injectable, ContactController, Body, Controller, Get, Param (+23 more)
### Community 3 - "UsersService"
Cohesion: 0.07
Nodes (33): JwtPayload, JwtStrategy, Injectable, AddressDto, ApiProperty, ApiPropertyOptional, IsBoolean, IsNotEmpty (+25 more)
Cohesion: 0.06
Nodes (37): AuthModule, Module, JwtPayload, JwtStrategy, Injectable, AddressDto, ApiProperty, ApiPropertyOptional (+29 more)
### Community 4 - "CmsController"
Cohesion: 0.09
@ -347,12 +353,12 @@ Cohesion: 0.13
Nodes (15): BannersController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+7 more)
### Community 6 - "auth.controller.ts"
Cohesion: 0.07
Nodes (39): AuthController, ApiBadRequestResponse, ApiOkResponse, ApiOperation, ApiTags, Body, Controller, Post (+31 more)
Cohesion: 0.06
Nodes (41): AuthController, ApiBadRequestResponse, ApiOkResponse, ApiOperation, ApiTags, Body, Controller, Post (+33 more)
### Community 7 - "app.module.ts"
Cohesion: 0.10
Nodes (25): AuthModule, Module, B2BModule, Module, BannersModule, Module, CmsModule, Module (+17 more)
Nodes (26): BannersModule, Module, CmsModule, Module, SmsModule, Global, Module, ContactModule (+18 more)
### Community 8 - "CreateVideoDto"
Cohesion: 0.07
@ -374,9 +380,13 @@ Nodes (32): compilerOptions, allowJs, esModuleInterop, incremental, isolatedModu
Cohesion: 0.08
Nodes (37): ClientLayout(), VerifyContent(), AddressModal(), AddressModalProps, AuthModal(), AuthModalProps, B2BPortal(), BackButton() (+29 more)
### Community 13 - "ZibalService"
Cohesion: 0.16
Nodes (4): PaymentService, Injectable, Injectable, ZibalService
### Community 14 - "ProductsService"
Cohesion: 0.09
Nodes (19): GetProductsDto, ApiPropertyOptional, IsEnum, IsOptional, IsString, ProductsController, ApiOperation, ApiTags (+11 more)
Cohesion: 0.12
Nodes (13): ProductsController, ApiOperation, ApiTags, Body, Controller, Get, Param, Patch (+5 more)
### Community 15 - "lib/services/api.ts"
Cohesion: 0.08
@ -386,20 +396,24 @@ Nodes (17): metadata, ContactFormClient(), ContactInfoItem, PrescriptionUploadMo
Cohesion: 0.07
Nodes (30): HomeClient(), HomeClientProps, getHomeData(), Home(), metadata, metadata, EnamadBadge(), Footer() (+22 more)
### Community 18 - "MetricsController"
Cohesion: 0.20
Nodes (5): ApiExcludeController, MetricsController, Controller, Get, Res
### Community 19 - "B2B Inquiry Controller"
Cohesion: 0.13
Nodes (15): B2BController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get, Param (+7 more)
### Community 20 - "Category Management Controller"
Cohesion: 0.10
Nodes (16): CategoriesController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+8 more)
### Community 20 - "CategoriesController"
Cohesion: 0.09
Nodes (17): CategoriesController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+9 more)
### Community 21 - "auth.service.ts"
Cohesion: 0.10
Nodes (10): AdminLoginInput, AuthService, LoginInput, RegisterInput, Injectable, RedisModule, Global, Module (+2 more)
### Community 21 - "RedisService"
Cohesion: 0.15
Nodes (7): CouponTargetInput, PaginationQuery, RedisModule, Global, Module, RedisService, Injectable
### Community 22 - "MediaController"
Cohesion: 0.10
Cohesion: 0.11
Nodes (16): MediaController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+8 more)
### Community 23 - "Ingredient Management Controller"
@ -407,16 +421,16 @@ Cohesion: 0.13
Nodes (14): IngredientsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
### Community 24 - "adminRoutes.tsx"
Cohesion: 0.08
Nodes (18): App(), ContactInfoItem, ContactSubmission, CategoryDist, DashboardData, PatternItem, SmsConfigState, SmsLogItem (+10 more)
Cohesion: 0.14
Nodes (10): App(), ContactInfoItem, ContactSubmission, GROUP_PAGE_MAP, GROUPS, PAGE_TABS, AdminRouteConfig, ContactSubmissions (+2 more)
### Community 25 - "admin.module.ts"
Cohesion: 0.10
Nodes (14): AdminModule, Module, PetQuery, PetsService, Injectable, ReportsController, ApiBearerAuth, ApiOperation (+6 more)
Cohesion: 0.11
Nodes (13): AdminModule, Module, PetsService, Injectable, ReportsController, ApiBearerAuth, ApiOperation, ApiTags (+5 more)
### Community 26 - "ConfirmModal.tsx"
Cohesion: 0.10
Nodes (16): ConfirmModal(), ConfirmModalProps, HeroBanner, VetTestimonial, Pet, fetchVideosList(), Video, Videos() (+8 more)
Cohesion: 0.11
Nodes (12): ConfirmModal(), ConfirmModalProps, HeroBanner, VetTestimonial, Media, WholesaleRequest, ProductItem, WikiTerm (+4 more)
### Community 27 - "Prescription Review Controller"
Cohesion: 0.14
@ -431,28 +445,28 @@ Cohesion: 0.13
Nodes (14): TestimonialsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
### Community 30 - "src/services/api.ts"
Cohesion: 0.10
Nodes (27): Layout(), ProtectedRoute(), menuGroups, Sidebar(), SidebarProps, SEARCHABLE_PAGES, Topbar(), TopbarProps (+19 more)
Cohesion: 0.16
Nodes (16): Layout(), ProtectedRoute(), menuGroups, Sidebar(), SidebarProps, SEARCHABLE_PAGES, Topbar(), TopbarProps (+8 more)
### Community 31 - "Spinner.tsx"
Cohesion: 0.08
Nodes (23): Media, MediaSelector(), MediaSelectorProps, Spinner(), BlogPost, Category, Category, Product (+15 more)
Cohesion: 0.09
Nodes (20): Media, MediaSelector(), MediaSelectorProps, Spinner(), BlogPost, Category, BannersManager, Blogs (+12 more)
### Community 32 - "useCartStore"
Cohesion: 0.12
Nodes (16): metadata, ArchiveProductCard(), ProductCard(), Header(), MENU_ICONS, OrderSuccess(), OrderTracking(), PetProfile() (+8 more)
### Community 33 - "ZibalService"
Cohesion: 0.06
Nodes (37): AdminTransactionFilterDto, ApiPropertyOptional, IsNumber, IsOptional, IsString, Type, InitiatePaymentDto, InitiateWalletTopupDto (+29 more)
### Community 33 - "PaymentController"
Cohesion: 0.19
Nodes (17): PaymentController, ApiBadRequestResponse, ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags, Body, Controller (+9 more)
### Community 34 - "main.ts"
Cohesion: 0.14
Nodes (9): CustomHttpExceptionFilter, Catch, PrismaExceptionFilter, Catch, DecimalInterceptor, Injectable, ApiErrorResponse, ErrorDetailField (+1 more)
Cohesion: 0.11
Nodes (11): AppModule, Module, CustomHttpExceptionFilter, Catch, PrismaExceptionFilter, Catch, DecimalInterceptor, Injectable (+3 more)
### Community 35 - "ContactService"
Cohesion: 0.13
Nodes (11): ContactController, Body, Controller, Get, Param, Post, Put, Query (+3 more)
### Community 35 - "admin.ts"
Cohesion: 0.12
Nodes (13): B2BManager, FinancialSettingsPage, SmartAdvisorManager, SystemSettingsPage, AdminLoginPayload, B2BInquiry, FinancialSettings, PartnerAccount (+5 more)
### Community 36 - "Backend TypeScript Config"
Cohesion: 0.09
@ -462,9 +476,9 @@ Nodes (22): compilerOptions, allowSyntheticDefaultImports, baseUrl, declaration,
Cohesion: 0.09
Nodes (22): compilerOptions, allowImportingTsExtensions, erasableSyntaxOnly, jsx, lib, module, moduleDetection, moduleResolution (+14 more)
### Community 38 - "Coupons.tsx"
Cohesion: 0.09
Nodes (15): Pagination(), PaginationProps, Coupon, CouponFormData, CouponModalProps, CouponTarget, Media, Stats (+7 more)
### Community 38 - "Products.tsx"
Cohesion: 0.13
Nodes (11): Pagination(), PaginationProps, Pet, Category, Product, GatewayHealth, Stats, Transaction (+3 more)
### Community 39 - "dependencies"
Cohesion: 0.10
@ -478,9 +492,9 @@ Nodes (20): compilerOptions, allowImportingTsExtensions, erasableSyntaxOnly, lib
Cohesion: 0.13
Nodes (15): BlogsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+7 more)
### Community 42 - "WholesaleApplyDto"
Cohesion: 0.10
Nodes (20): ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, WholesaleApplyDto, ApiBearerAuth, ApiOperation (+12 more)
### Community 42 - "WholesaleService"
Cohesion: 0.14
Nodes (14): ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get, Param, Post (+6 more)
### Community 43 - "devDependencies"
Cohesion: 0.13
@ -494,9 +508,9 @@ Nodes (14): ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, De
Cohesion: 0.16
Nodes (10): SeoController, ApiOperation, ApiTags, Controller, Get, Param, SeoModule, Module (+2 more)
### Community 46 - "OrdersController"
Cohesion: 0.13
Nodes (16): OrdersController, ApiBadRequestResponse, ApiBearerAuth, ApiCreatedResponse, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags (+8 more)
### Community 46 - "PaginationDto"
Cohesion: 0.20
Nodes (9): PaginationDto, SortOrder, ApiPropertyOptional, IsEnum, IsOptional, IsString, Type, IsInt (+1 more)
### Community 47 - "Project Build Scripts"
Cohesion: 0.11
@ -508,7 +522,7 @@ Nodes (10): HomeController, ApiOkResponse, ApiOperation, ApiTags, Controller, Ge
### Community 49 - "devDependencies"
Cohesion: 0.11
Nodes (19): autoprefixer, devDependencies, autoprefixer, eslint, @eslint/js, postcss, @tailwindcss/postcss, @types/node (+11 more)
Nodes (19): autoprefixer, devDependencies, autoprefixer, eslint, @eslint/js, globals, postcss, @types/node (+11 more)
### Community 50 - "Database Seeding Logic"
Cohesion: 0.17
@ -548,27 +562,27 @@ Nodes (11): PetsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Cont
### Community 59 - "PrismaService"
Cohesion: 0.08
Nodes (18): ApiExcludeController, CouponTargetInput, PaginationQuery, CategoryQuery, MetricsController, Controller, Get, Res (+10 more)
Nodes (19): BlogQuery, PetQuery, WikiQuery, AdminLoginInput, LoginInput, RegisterInput, MeliPayamakPattern, MeliPayamakResponse (+11 more)
### Community 60 - "Jest Testing Config"
Cohesion: 0.15
Nodes (13): jest, collectCoverageFrom, coverageDirectory, moduleFileExtensions, rootDir, testEnvironment, testRegex, transform (+5 more)
### Community 61 - "PaginationDto"
Cohesion: 0.13
Nodes (13): PaginationDto, SortOrder, ApiPropertyOptional, IsEnum, IsOptional, IsString, Type, Module (+5 more)
### Community 61 - "WikiController"
Cohesion: 0.20
Nodes (7): ApiTags, Controller, WikiController, Module, WikiModule, Injectable, WikiService
### Community 62 - "SettingsService"
Cohesion: 0.11
Nodes (4): SmsLogQuery, ScientificTermData, SettingsService, Injectable
### Community 62 - "api"
Cohesion: 0.20
Nodes (8): CategoryDist, DashboardData, fetchVideosList(), Video, Videos(), Dashboard, Videos, api
### Community 63 - "FE-001"
Cohesion: 0.06
Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, Architecture Overview & Confirmed Strengths, Category, Completion Statement, Confidence (+23 more)
### Community 64 - "payment.module.ts"
### Community 64 - "zibal.service.ts"
Cohesion: 0.16
Nodes (10): SmsModule, Global, Module, ContactModule, Module, PaymentModule, Module, ZibalInquiryResponse (+2 more)
Nodes (9): GatewayHealthResult, IPaymentGateway, PaymentInquiryResult, PaymentRequestOptions, PaymentRequestResult, PaymentVerifyResult, ZibalInquiryResponse, ZibalRequestResponse (+1 more)
### Community 66 - "App Health Controller"
Cohesion: 0.29
@ -579,8 +593,8 @@ Cohesion: 0.12
Nodes (17): dependencies, axios, lucide-react, motion, next, react, react-dom, sonner (+9 more)
### Community 68 - "OrdersService"
Cohesion: 0.12
Nodes (15): CreateOrderDto, OrderItemDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional (+7 more)
Cohesion: 0.06
Nodes (35): CreateOrderDto, OrderItemDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional (+27 more)
### Community 69 - "Integrity Validation Scripts"
Cohesion: 0.20
@ -614,9 +628,9 @@ Nodes (3): ErrorBoundary, Props, State
Cohesion: 0.22
Nodes (8): name, private, scripts, build, dev, lint, start, version
### Community 77 - "WikiController"
Cohesion: 0.21
Nodes (9): ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Param, Query (+1 more)
### Community 77 - ".findAll"
Cohesion: 0.32
Nodes (6): ApiNotFoundResponse, ApiOkResponse, ApiOperation, Get, Param, Query
### Community 79 - "VPN Utility Scripts"
Cohesion: 0.62
@ -682,18 +696,10 @@ Nodes (3): COMPOSE_DOCKER_CLI_BUILD, DOCKER_BUILDKIT, deploy.sh script
Cohesion: 0.06
Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, Category, Completion Statement, Confidence, Database and Data Integrity Audit Report (+23 more)
### Community 103 - "BlogsService"
Cohesion: 0.22
Nodes (3): BlogQuery, BlogsService, Injectable
### Community 109 - "Auth Architecture and Planning"
Cohesion: 0.67
Nodes (3): ADR-AUTH-001: Admin Panel Authentication Architecture & Token Management, Master Task Backlog (Phase 3.3), Phase 3 Master Execution Plan
### Community 117 - "WikiService"
Cohesion: 0.22
Nodes (3): Injectable, WikiQuery, WikiService
### Community 118 - "TS-001"
Cohesion: 0.06
Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, Category, Completion Statement, Confidence, Dependencies (+23 more)
@ -702,9 +708,9 @@ Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternati
Cohesion: 0.06
Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, Category, Completion Statement, Confidence, Dependencies (+23 more)
### Community 120 - "ValidateCouponDto"
Cohesion: 0.50
Nodes (4): IsNotEmpty, IsNumber, IsString, ValidateCouponDto
### Community 120 - "AdminTransactionFilterDto"
Cohesion: 0.22
Nodes (7): AdminTransactionFilterDto, ApiPropertyOptional, IsNumber, IsOptional, IsString, Type, IsIn
### Community 126 - "Typography and Font Assets"
Cohesion: 0.67
@ -723,8 +729,8 @@ Cohesion: 0.07
Nodes (26): For /graphify add and --watch, For /graphify query, For the commit hook and native CLAUDE.md integration, For --update and --cluster-only, /graphify, Honesty Rules, Interpreter guard for subcommands, Part A - Structural extraction for code files (+18 more)
### Community 130 - "JwtAuthGuard"
Cohesion: 0.18
Nodes (7): JwtAuthGuard, Injectable, ROLES_KEY, RequestWithUser, RolesGuard, Injectable, UserReqPayload
Cohesion: 0.15
Nodes (9): JwtAuthGuard, Injectable, B2BModule, Module, ROLES_KEY, RequestWithUser, RolesGuard, Injectable (+1 more)
### Community 131 - "راهنمای تست سیستم (Software Testing)"
Cohesion: 0.07
@ -954,25 +960,49 @@ Nodes (3): Expanding the ESLint configuration, React Compiler, React + TypeScrip
Cohesion: 0.50
Nodes (3): Deploy on Vercel, Getting Started, Learn More
### Community 284 - "wholesale.controller.ts"
Cohesion: 0.31
Nodes (6): ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, WholesaleApplyDto
### Community 285 - "InitiatePaymentDto"
Cohesion: 0.43
Nodes (7): InitiatePaymentDto, InitiateWalletTopupDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString
### Community 286 - "GetProductsDto"
Cohesion: 0.29
Nodes (6): GetProductsDto, ApiPropertyOptional, IsEnum, IsOptional, IsString, Query
### Community 287 - "Coupons.tsx"
Cohesion: 0.25
Nodes (5): Coupon, CouponFormData, CouponModalProps, CouponTarget, Coupons
### Community 288 - "SmsSettingsPage.tsx"
Cohesion: 0.29
Nodes (5): PatternItem, SmsConfigState, SmsLogItem, SmsLogStats, SmsSettingsPage
### Community 289 - "ZibalCallbackQueryDto"
Cohesion: 0.40
Nodes (4): ApiPropertyOptional, IsOptional, IsString, ZibalCallbackQueryDto
## Knowledge Gaps
- **1179 isolated node(s):** `$schema`, `collection`, `sourceRoot`, `deleteOutDir`, `name` (+1174 more)
- **1181 isolated node(s):** `$schema`, `collection`, `sourceRoot`, `deleteOutDir`, `name` (+1176 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **113 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `ApiResponse` connect `src/services/api.ts` to `pets/pets.controller.ts`, `UsersService`, `auth.controller.ts`, `BlogsController`, `WikiController`, `OrdersController`, `ProductsService`, `Home Data Module`?**
- **Why does `ApiResponse` connect `src/services/api.ts` to `pets/pets.controller.ts`, `UsersService`, `OrdersService`, `admin.ts`, `auth.controller.ts`, `BlogsController`, `ProductsService`, `Home Data Module`, `WikiController`?**
_High betweenness centrality (0.039) - this node is a cross-community bridge._
- **Why does `Roles()` connect `Roles` to `ZibalService`, `JwtAuthGuard`, `ContactService`, `CmsController`, `BannersService`, `WholesaleApplyDto`, `ProductsService`, `B2B Inquiry Controller`, `Ingredient Management Controller`, `Prescription Review Controller`, `Smart Advisor Controller`, `Testimonials Management Controller`, `SettingsService`?**
_High betweenness centrality (0.037) - this node is a cross-community bridge._
- **Why does `JwtAuthGuard` connect `JwtAuthGuard` to `AdminService`, `pets/pets.controller.ts`, `UsersService`, `CmsController`, `OrdersService`, `CreateVideoDto`, `MediaController`, `admin.module.ts`, `SettingsService`?**
_High betweenness centrality (0.022) - this node is a cross-community bridge._
- **Why does `Roles()` connect `Roles` to `PaymentController`, `JwtAuthGuard`, `CmsController`, `BannersService`, `WholesaleService`, `ProductsService`, `B2B Inquiry Controller`, `wholesale.controller.ts`, `Ingredient Management Controller`, `Prescription Review Controller`, `Smart Advisor Controller`, `Testimonials Management Controller`?**
_High betweenness centrality (0.029) - this node is a cross-community bridge._
- **Why does `PrismaService` connect `PrismaService` to `pets/pets.controller.ts`, `JwtAuthGuard`, `Roles`, `CmsController`, `BannersService`, `UsersService`, `app.module.ts`, `CreateVideoDto`, `ZibalService`, `ProductsService`, `MetricsController`, `B2B Inquiry Controller`, `CategoriesController`, `RedisService`, `MediaController`, `Ingredient Management Controller`, `admin.module.ts`, `Prescription Review Controller`, `Smart Advisor Controller`, `Testimonials Management Controller`, `wholesale.controller.ts`, `WholesaleService`, `seo.module.ts`, `Home Data Module`, `WikiController`, `zibal.service.ts`, `OrdersService`, `BlogsController`, `BlogsService`, `WikiService`?**
_High betweenness centrality (0.025) - this node is a cross-community bridge._
- **What connects `$schema`, `collection`, `sourceRoot` to the rest of the system?**
_1179 weakly-connected nodes found - possible documentation gaps or missing edges._
_1181 weakly-connected nodes found - possible documentation gaps or missing edges._
- **Should `AdminService` be split into smaller, more focused modules?**
_Cohesion score 0.06841046277665996 - nodes in this community are weakly interconnected._
_Cohesion score 0.06690140845070422 - nodes in this community are weakly interconnected._
- **Should `pets/pets.controller.ts` be split into smaller, more focused modules?**
_Cohesion score 0.053923541247484906 - nodes in this community are weakly interconnected._
- **Should `UsersService` be split into smaller, more focused modules?**
_Cohesion score 0.06766917293233082 - nodes in this community are weakly interconnected._
_Cohesion score 0.0528169014084507 - nodes in this community are weakly interconnected._
- **Should `Roles` be split into smaller, more focused modules?**
_Cohesion score 0.051446321102698506 - nodes in this community are weakly interconnected._

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,16 @@
# Graph Report - canina (2026-08-16)
## Corpus Check
- 464 files · ~680,159 words
- 467 files · ~685,071 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 3257 nodes · 5318 edges · 291 communities (178 shown, 113 thin omitted)
- Extraction: 96% EXTRACTED · 4% INFERRED · 0% AMBIGUOUS · INFERRED: 188 edges (avg confidence: 0.79)
- 3274 nodes · 5352 edges · 289 communities (175 shown, 114 thin omitted)
- Extraction: 96% EXTRACTED · 4% INFERRED · 0% AMBIGUOUS · INFERRED: 189 edges (avg confidence: 0.79)
- Token cost: 0 input · 0 output
## Graph Freshness
- Built from commit: `5ace474d`
- Built from commit: `5c13dd2f`
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
- Run `graphify update .` after code changes (no API cost).
@ -20,17 +20,17 @@
- Roles
- UsersService
- CmsController
- BannersService
- auth.controller.ts
- SmsService
- AuthController
- app.module.ts
- CreateVideoDto
- ProductService
- SmartAdvisor.tsx
- VideosService
- products.ts
- ContactService
- compilerOptions
- toPersian
- ZibalService
- auth.controller.ts
- ProductsService
- lib/services/api.ts
- useCartStore
- eslint
- useSettingsStore
- MetricsController
@ -45,15 +45,15 @@
- Prescription Review Controller
- Smart Advisor Controller
- Testimonials Management Controller
- src/services/api.ts
- api
- Spinner.tsx
- useCartStore
- PaymentController
- PetProfile.tsx
- ZibalService
- main.ts
- admin.ts
- src/services/api.ts
- Backend TypeScript Config
- App TypeScript Config
- Products.tsx
- Pagination.tsx
- dependencies
- Node TypeScript Config
- Admin Blog Controller
@ -69,17 +69,17 @@
- Prisma Database Migrations
- dependencies
- UI Skeleton and Tables
- components/Skeleton.tsx
- auth.service.ts
- BE-001
- VetGallery.tsx
- SafeImage.tsx
- NPM Lifecycle Scripts
- Pet Management API
- PrismaService
- Jest Testing Config
- WikiController
- api
- videos.controller.ts
- FE-001
- zibal.service.ts
- VerifyOtpDto
- rules/graphify.md
- App Health Controller
- dependencies
@ -89,7 +89,7 @@
- Analytics and Report Charts
- Task Orchestration Scripts
- Backend Package Config
- BlogsController
- RegisterDto
- React Error Boundary
- Application Package Config
- .findAll
@ -105,7 +105,7 @@
- Font Assets and Licenses
- Ledger Rebuild Scripts
- Evidence Validation Scripts
- Blog Listing Page
- CreateVideoDto
- Blog Post Detail Page
- @types/node
- devDependencies
@ -115,7 +115,7 @@
- Home Management DTOs
- Wiki Management DTOs
- Wiki Page Routing
- Network Status Banner
- ClientLayout.tsx
- Docker Deployment Scripts
- DB-001
- BlogsService
@ -132,11 +132,11 @@
- Manifest Data Generation
- Honest Manifest Synchronization
- Manifest Entry Synchronization
- WikiService
- SendOtpDto
- TS-001
- TEST-001
- AdminTransactionFilterDto
- @types/react-dom
- payment.service.ts
- UITexts.tsx
- Admin Panel TSConfig
- About Page Component
- Privacy Page Component
@ -222,7 +222,7 @@
- Phase 2 Final Quality Gate Summary Report
- Task Modifications Log
- Install
- .findAll
- BlogsController
- System Discovery
- Product Requirement Document (PRD)
- Baseline Command Plan & Reconciled Command History
@ -245,7 +245,7 @@
- 🔒 Security & Performance Review (09_devops_security)
- 👁️ UX & Persona Interface Review (08_visual_qa)
- Compiler Diagnostic Dispositions
- @eslint/eslintrc
- OrderService
- js-yaml
- globals
- prettier
@ -285,12 +285,10 @@
- tsconfig-paths
- @types/bcryptjs
- typescript-eslint
- wholesale.controller.ts
- InitiatePaymentDto
- GetProductsDto
- Coupons.tsx
- contact/page.tsx
- eslint-plugin-prettier
- eslint-config-next
- SmsSettingsPage.tsx
- ZibalCallbackQueryDto
- @tailwindcss/postcss
## God Nodes (most connected - your core abstractions)
@ -326,78 +324,74 @@
- **Rastikerdar Font Ecosystem** — frontend_application_public_fonts_shabnam_font_v5_0_1_readme, frontend_application_public_fonts_vazirmatn_v33_003_readme, vazir_font [EXTRACTED 0.95]
- **Canina Deployment Stack** — scripts_compose_prod, scripts_compose_stage [EXTRACTED 1.00]
## Communities (291 total, 113 thin omitted)
## Communities (289 total, 114 thin omitted)
### Community 0 - "AdminService"
Cohesion: 0.07
Nodes (22): AdminController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+14 more)
Cohesion: 0.06
Nodes (24): AdminController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+16 more)
### Community 1 - "pets/pets.controller.ts"
Cohesion: 0.05
Nodes (45): CreateHealthLogDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, CreatePetDto, ApiProperty (+37 more)
### Community 2 - "Roles"
Cohesion: 0.05
Nodes (31): Roles(), SmsService, Injectable, ContactController, Body, Controller, Get, Param (+23 more)
Cohesion: 0.06
Nodes (33): BannersController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+25 more)
### Community 3 - "UsersService"
Cohesion: 0.06
Nodes (37): AuthModule, Module, JwtPayload, JwtStrategy, Injectable, AddressDto, ApiProperty, ApiPropertyOptional (+29 more)
Nodes (36): JwtPayload, JwtStrategy, Injectable, AddressDto, ApiProperty, ApiPropertyOptional, IsBoolean, IsNotEmpty (+28 more)
### Community 4 - "CmsController"
Cohesion: 0.09
Nodes (24): CmsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+16 more)
### Community 5 - "BannersService"
Cohesion: 0.13
Nodes (15): BannersController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+7 more)
### Community 6 - "auth.controller.ts"
Cohesion: 0.06
Nodes (41): AuthController, ApiBadRequestResponse, ApiOkResponse, ApiOperation, ApiTags, Body, Controller, Post (+33 more)
### Community 6 - "AuthController"
Cohesion: 0.36
Nodes (9): AuthController, ApiBadRequestResponse, ApiOkResponse, ApiOperation, ApiTags, Body, Controller, Post (+1 more)
### Community 7 - "app.module.ts"
Cohesion: 0.10
Nodes (26): BannersModule, Module, CmsModule, Module, SmsModule, Global, Module, ContactModule (+18 more)
Cohesion: 0.09
Nodes (28): B2BModule, Module, BannersModule, Module, CmsModule, Module, SmsModule, Global (+20 more)
### Community 8 - "CreateVideoDto"
Cohesion: 0.07
Nodes (31): CreateVideoDto, ApiProperty, ApiPropertyOptional, IsBoolean, IsNotEmpty, IsOptional, IsString, UpdateVideoDto (+23 more)
### Community 8 - "VideosService"
Cohesion: 0.12
Nodes (16): ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete, Get (+8 more)
### Community 9 - "ProductService"
Cohesion: 0.07
Nodes (30): CatalogClient(), metadata, metadata, metadata, ArchivePage(), CATEGORY_MAP, ICON_MAP, BlogPost (+22 more)
### Community 9 - "products.ts"
Cohesion: 0.06
Nodes (30): Blog(), getBlogs(), metadata, CatalogClient(), metadata, metadata, metadata, BlogPage() (+22 more)
### Community 10 - "SmartAdvisor.tsx"
Cohesion: 0.32
Nodes (6): CURRENT_SYMPTOMS, MEDICAL_HISTORIES, SmartAdvisor(), SmartAdvisorProps, UIState, useUIStore
### Community 10 - "ContactService"
Cohesion: 0.13
Nodes (11): ContactController, Body, Controller, Get, Param, Post, Put, Query (+3 more)
### Community 11 - "compilerOptions"
Cohesion: 0.06
Nodes (32): compilerOptions, allowJs, esModuleInterop, incremental, isolatedModules, jsx, lib, module (+24 more)
### Community 12 - "toPersian"
Cohesion: 0.08
Nodes (37): ClientLayout(), VerifyContent(), AddressModal(), AddressModalProps, AuthModal(), AuthModalProps, B2BPortal(), BackButton() (+29 more)
Cohesion: 0.12
Nodes (24): AddressModal(), AddressModalProps, BackButton(), BackButtonProps, CheckoutPage(), DeleteConfirmModal(), DeleteConfirmModalProps, HeaderButton() (+16 more)
### Community 13 - "ZibalService"
### Community 13 - "auth.controller.ts"
Cohesion: 0.16
Nodes (4): PaymentService, Injectable, Injectable, ZibalService
Nodes (11): AdminLoginDto, ApiProperty, IsEmail, IsNotEmpty, IsString, MinLength, LoginDto, ApiProperty (+3 more)
### Community 14 - "ProductsService"
Cohesion: 0.12
Nodes (13): ProductsController, ApiOperation, ApiTags, Body, Controller, Get, Param, Patch (+5 more)
Cohesion: 0.09
Nodes (19): GetProductsDto, ApiPropertyOptional, IsEnum, IsOptional, IsString, ProductsController, ApiOperation, ApiTags (+11 more)
### Community 15 - "lib/services/api.ts"
### Community 15 - "useCartStore"
Cohesion: 0.08
Nodes (17): metadata, ContactFormClient(), ContactInfoItem, PrescriptionUploadModal(), PrescriptionUploadModalProps, api, ApiErrorPayload, ApiErr (+9 more)
Nodes (31): VerifyContent(), AuthModal(), AuthModalProps, B2BPortal(), CartDrawer(), ContactInfoItem, Header(), MENU_ICONS (+23 more)
### Community 17 - "useSettingsStore"
Cohesion: 0.07
Nodes (30): HomeClient(), HomeClientProps, getHomeData(), Home(), metadata, metadata, EnamadBadge(), Footer() (+22 more)
Cohesion: 0.09
Nodes (31): HomeClient(), HomeClientProps, getHomeData(), Home(), metadata, metadata, EnamadBadge(), Hero() (+23 more)
### Community 18 - "MetricsController"
Cohesion: 0.20
Cohesion: 0.29
Nodes (5): ApiExcludeController, MetricsController, Controller, Get, Res
### Community 19 - "B2B Inquiry Controller"
@ -409,8 +403,8 @@ Cohesion: 0.09
Nodes (17): CategoriesController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+9 more)
### Community 21 - "RedisService"
Cohesion: 0.15
Nodes (7): CouponTargetInput, PaginationQuery, RedisModule, Global, Module, RedisService, Injectable
Cohesion: 0.11
Nodes (7): AppModule, Module, RedisModule, Global, Module, RedisService, Injectable
### Community 22 - "MediaController"
Cohesion: 0.11
@ -421,16 +415,16 @@ Cohesion: 0.13
Nodes (14): IngredientsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
### Community 24 - "adminRoutes.tsx"
Cohesion: 0.14
Nodes (10): App(), ContactInfoItem, ContactSubmission, GROUP_PAGE_MAP, GROUPS, PAGE_TABS, AdminRouteConfig, ContactSubmissions (+2 more)
Cohesion: 0.12
Nodes (11): App(), ContactInfoItem, ContactSubmission, CategoryDist, DashboardData, AdminRouteConfig, ContactSubmissions, Dashboard (+3 more)
### Community 25 - "admin.module.ts"
Cohesion: 0.11
Nodes (13): AdminModule, Module, PetsService, Injectable, ReportsController, ApiBearerAuth, ApiOperation, ApiTags (+5 more)
Cohesion: 0.10
Nodes (14): AdminModule, Module, PetQuery, PetsService, Injectable, ReportsController, ApiBearerAuth, ApiOperation (+6 more)
### Community 26 - "ConfirmModal.tsx"
Cohesion: 0.11
Nodes (12): ConfirmModal(), ConfirmModalProps, HeroBanner, VetTestimonial, Media, WholesaleRequest, ProductItem, WikiTerm (+4 more)
Cohesion: 0.08
Nodes (19): ConfirmModal(), ConfirmModalProps, HeroBanner, VetTestimonial, Coupon, CouponFormData, CouponModalProps, CouponTarget (+11 more)
### Community 27 - "Prescription Review Controller"
Cohesion: 0.14
@ -444,29 +438,29 @@ Nodes (14): SmartAdvisorController, ApiBearerAuth, ApiOperation, ApiTags, Body,
Cohesion: 0.13
Nodes (14): TestimonialsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
### Community 30 - "src/services/api.ts"
Cohesion: 0.16
Nodes (16): Layout(), ProtectedRoute(), menuGroups, Sidebar(), SidebarProps, SEARCHABLE_PAGES, Topbar(), TopbarProps (+8 more)
### Community 30 - "api"
Cohesion: 0.24
Nodes (8): Layout(), menuGroups, Sidebar(), SidebarProps, SEARCHABLE_PAGES, Topbar(), TopbarProps, api
### Community 31 - "Spinner.tsx"
Cohesion: 0.09
Nodes (20): Media, MediaSelector(), MediaSelectorProps, Spinner(), BlogPost, Category, BannersManager, Blogs (+12 more)
### Community 32 - "useCartStore"
Cohesion: 0.12
Nodes (16): metadata, ArchiveProductCard(), ProductCard(), Header(), MENU_ICONS, OrderSuccess(), OrderTracking(), PetProfile() (+8 more)
### Community 32 - "PetProfile.tsx"
Cohesion: 0.08
Nodes (27): metadata, ArchivePage(), ArchiveProductCard(), CATEGORY_MAP, ICON_MAP, FeaturedProducts(), ProductCard(), OrderSuccess() (+19 more)
### Community 33 - "PaymentController"
Cohesion: 0.19
Nodes (17): PaymentController, ApiBadRequestResponse, ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags, Body, Controller (+9 more)
### Community 33 - "ZibalService"
Cohesion: 0.05
Nodes (41): InitiatePaymentDto, InitiateWalletTopupDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, ApiPropertyOptional (+33 more)
### Community 34 - "main.ts"
Cohesion: 0.11
Nodes (11): AppModule, Module, CustomHttpExceptionFilter, Catch, PrismaExceptionFilter, Catch, DecimalInterceptor, Injectable (+3 more)
Cohesion: 0.14
Nodes (9): CustomHttpExceptionFilter, Catch, PrismaExceptionFilter, Catch, DecimalInterceptor, Injectable, ApiErrorResponse, ErrorDetailField (+1 more)
### Community 35 - "admin.ts"
### Community 35 - "src/services/api.ts"
Cohesion: 0.12
Nodes (13): B2BManager, FinancialSettingsPage, SmartAdvisorManager, SystemSettingsPage, AdminLoginPayload, B2BInquiry, FinancialSettings, PartnerAccount (+5 more)
Nodes (20): ProtectedRoute(), Login(), B2BManager, FinancialSettingsPage, SmartAdvisorManager, ApiErrorPayload, failedQueue, useAdminAuthStore (+12 more)
### Community 36 - "Backend TypeScript Config"
Cohesion: 0.09
@ -476,9 +470,9 @@ Nodes (22): compilerOptions, allowSyntheticDefaultImports, baseUrl, declaration,
Cohesion: 0.09
Nodes (22): compilerOptions, allowImportingTsExtensions, erasableSyntaxOnly, jsx, lib, module, moduleDetection, moduleResolution (+14 more)
### Community 38 - "Products.tsx"
Cohesion: 0.13
Nodes (11): Pagination(), PaginationProps, Pet, Category, Product, GatewayHealth, Stats, Transaction (+3 more)
### Community 38 - "Pagination.tsx"
Cohesion: 0.11
Nodes (13): Pagination(), PaginationProps, Media, Pet, GatewayHealth, Stats, Transaction, ProductItem (+5 more)
### Community 39 - "dependencies"
Cohesion: 0.10
@ -498,7 +492,7 @@ Nodes (14): ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get, Param,
### Community 43 - "devDependencies"
Cohesion: 0.13
Nodes (15): eslint-config-next, devDependencies, eslint, eslint-config-next, jsdom, tailwindcss, @tailwindcss/postcss, @types/node (+7 more)
Nodes (15): devDependencies, eslint, jsdom, tailwindcss, @tailwindcss/postcss, @types/node, @types/react-dom, @vitejs/plugin-react (+7 more)
### Community 44 - "Generic CRUD Controller"
Cohesion: 0.13
@ -509,8 +503,8 @@ Cohesion: 0.16
Nodes (10): SeoController, ApiOperation, ApiTags, Controller, Get, Param, SeoModule, Module (+2 more)
### Community 46 - "PaginationDto"
Cohesion: 0.20
Nodes (9): PaginationDto, SortOrder, ApiPropertyOptional, IsEnum, IsOptional, IsString, Type, IsInt (+1 more)
Cohesion: 0.14
Nodes (13): BlogsModule, Module, BlogsService, Injectable, PaginationDto, SortOrder, ApiPropertyOptional, IsEnum (+5 more)
### Community 47 - "Project Build Scripts"
Cohesion: 0.11
@ -540,17 +534,17 @@ Nodes (21): dependencies, axios, lucide-react, react, react-dom, react-hot-toast
Cohesion: 0.18
Nodes (11): Skeleton(), Order, OrderItem, Orders(), statusStyles, toPersianDigits(), UserRecord, Orders (+3 more)
### Community 54 - "components/Skeleton.tsx"
Cohesion: 0.33
Nodes (4): OrderRowSkeleton(), PetProfileSkeleton(), Skeleton(), SkeletonProps
### Community 54 - "auth.service.ts"
Cohesion: 0.16
Nodes (7): AuthModule, Module, AdminLoginInput, AuthService, LoginInput, RegisterInput, Injectable
### Community 55 - "BE-001"
Cohesion: 0.06
Nodes (32): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, BE-001, Category, Completion Statement, Confidence (+24 more)
### Community 56 - "VetGallery.tsx"
Cohesion: 0.22
Nodes (8): DisplayVideoItem, FALLBACK_VIDEOS, TestimonialItem, VetGallery(), FALLBACK_VIDEOS, VideosPage(), Video, videoService
### Community 56 - "SafeImage.tsx"
Cohesion: 0.17
Nodes (10): ProductDetailModalProps, SafeImage(), SafeImageProps, DisplayVideoItem, FALLBACK_VIDEOS, TestimonialItem, FALLBACK_VIDEOS, VideosPage() (+2 more)
### Community 57 - "NPM Lifecycle Scripts"
Cohesion: 0.14
@ -561,8 +555,8 @@ Cohesion: 0.15
Nodes (11): PetsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Controller, Delete, Get (+3 more)
### Community 59 - "PrismaService"
Cohesion: 0.08
Nodes (19): BlogQuery, PetQuery, WikiQuery, AdminLoginInput, LoginInput, RegisterInput, MeliPayamakPattern, MeliPayamakResponse (+11 more)
Cohesion: 0.06
Nodes (21): BlogQuery, Injectable, WikiQuery, WikiService, MeliPayamakPattern, MeliPayamakResponse, SendPatternSmsOptions, SmsConfig (+13 more)
### Community 60 - "Jest Testing Config"
Cohesion: 0.15
@ -572,17 +566,17 @@ Nodes (13): jest, collectCoverageFrom, coverageDirectory, moduleFileExtensions,
Cohesion: 0.20
Nodes (7): ApiTags, Controller, WikiController, Module, WikiModule, Injectable, WikiService
### Community 62 - "api"
Cohesion: 0.20
Nodes (8): CategoryDist, DashboardData, fetchVideosList(), Video, Videos(), Dashboard, Videos, api
### Community 62 - "videos.controller.ts"
Cohesion: 0.22
Nodes (7): GetVideosQueryDto, ApiPropertyOptional, IsBoolean, IsOptional, Module, VideosModule, Transform
### Community 63 - "FE-001"
Cohesion: 0.06
Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, Architecture Overview & Confirmed Strengths, Category, Completion Statement, Confidence (+23 more)
### Community 64 - "zibal.service.ts"
Cohesion: 0.16
Nodes (9): GatewayHealthResult, IPaymentGateway, PaymentInquiryResult, PaymentRequestOptions, PaymentRequestResult, PaymentVerifyResult, ZibalInquiryResponse, ZibalRequestResponse (+1 more)
### Community 64 - "VerifyOtpDto"
Cohesion: 0.22
Nodes (6): ApiProperty, IsNotEmpty, IsString, Matches, VerifyOtpDto, Length
### Community 66 - "App Health Controller"
Cohesion: 0.29
@ -616,9 +610,9 @@ Nodes (8): cmd_next_task(), cmd_progress(), cmd_reset(), cmd_status(), cmd_unblo
Cohesion: 0.22
Nodes (8): author, description, license, name, prisma, seed, private, version
### Community 74 - "BlogsController"
Cohesion: 0.20
Nodes (7): BlogsController, ApiTags, Controller, BlogsModule, Module, BlogsService, Injectable
### Community 74 - "RegisterDto"
Cohesion: 0.22
Nodes (8): RegisterDto, ApiProperty, ApiPropertyOptional, IsEmail, IsNotEmpty, IsOptional, IsString, MinLength
### Community 75 - "React Error Boundary"
Cohesion: 0.22
@ -672,9 +666,9 @@ Nodes (4): evidenceList, ledger, mandatoryMap, mandatoryScope
Cohesion: 0.40
Nodes (4): activeFiles, errors, validationOutput, warnings
### Community 90 - "Blog Listing Page"
Cohesion: 0.50
Nodes (4): Blog(), getBlogs(), metadata, BlogPage()
### Community 90 - "CreateVideoDto"
Cohesion: 0.25
Nodes (8): CreateVideoDto, ApiProperty, ApiPropertyOptional, IsBoolean, IsNotEmpty, IsOptional, IsString, UpdateVideoDto
### Community 91 - "Blog Post Detail Page"
Cohesion: 0.60
@ -682,12 +676,16 @@ Nodes (4): BlogPostPage(), generateMetadata(), getBlog(), revalidate
### Community 93 - "devDependencies"
Cohesion: 0.22
Nodes (9): devDependencies, eslint-plugin-prettier, @types/passport-jwt, @types/supertest, typescript, typescript, eslint-plugin-prettier, @types/passport-jwt (+1 more)
Nodes (9): devDependencies, @eslint/eslintrc, @types/passport-jwt, @types/supertest, typescript, typescript, @eslint/eslintrc, @types/passport-jwt (+1 more)
### Community 99 - "Wiki Page Routing"
Cohesion: 0.83
Nodes (3): generateMetadata(), getWikiTerm(), WikiTermPage()
### Community 100 - "ClientLayout.tsx"
Cohesion: 0.17
Nodes (8): ClientLayout(), Footer(), LoginModal(), LoginModalProps, MaintenancePage(), NetworkBanner(), useNetworkStatus(), NavigationTarget
### Community 101 - "Docker Deployment Scripts"
Cohesion: 0.50
Nodes (3): COMPOSE_DOCKER_CLI_BUILD, DOCKER_BUILDKIT, deploy.sh script
@ -700,6 +698,10 @@ Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternati
Cohesion: 0.67
Nodes (3): ADR-AUTH-001: Admin Panel Authentication Architecture & Token Management, Master Task Backlog (Phase 3.3), Phase 3 Master Execution Plan
### Community 117 - "SendOtpDto"
Cohesion: 0.25
Nodes (5): SendOtpDto, ApiProperty, IsNotEmpty, IsString, Matches
### Community 118 - "TS-001"
Cohesion: 0.06
Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, Category, Completion Statement, Confidence, Dependencies (+23 more)
@ -708,9 +710,13 @@ Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternati
Cohesion: 0.06
Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, Category, Completion Statement, Confidence, Dependencies (+23 more)
### Community 120 - "AdminTransactionFilterDto"
### Community 120 - "payment.service.ts"
Cohesion: 0.22
Nodes (7): AdminTransactionFilterDto, ApiPropertyOptional, IsNumber, IsOptional, IsString, Type, IsIn
Nodes (8): AdminTransactionFilterDto, ApiPropertyOptional, IsNumber, IsOptional, IsString, Type, ClientMetadata, IsIn
### Community 121 - "UITexts.tsx"
Cohesion: 0.33
Nodes (4): GROUP_PAGE_MAP, GROUPS, PAGE_TABS, UITexts
### Community 126 - "Typography and Font Assets"
Cohesion: 0.67
@ -729,8 +735,8 @@ Cohesion: 0.07
Nodes (26): For /graphify add and --watch, For /graphify query, For the commit hook and native CLAUDE.md integration, For --update and --cluster-only, /graphify, Honesty Rules, Interpreter guard for subcommands, Part A - Structural extraction for code files (+18 more)
### Community 130 - "JwtAuthGuard"
Cohesion: 0.15
Nodes (9): JwtAuthGuard, Injectable, B2BModule, Module, ROLES_KEY, RequestWithUser, RolesGuard, Injectable (+1 more)
Cohesion: 0.19
Nodes (7): JwtAuthGuard, Injectable, ROLES_KEY, RequestWithUser, RolesGuard, Injectable, UserReqPayload
### Community 131 - "راهنمای تست سیستم (Software Testing)"
Cohesion: 0.07
@ -880,9 +886,9 @@ Nodes (8): 1. `TASK-AUTH-001`, 2. `TASK-FIN-001`, 3. `DECISION-002`, 4. `TASK-VE
Cohesion: 0.22
Nodes (8): Arch Linux, bower, Install, npm, Shabnam Font, yarn, طریقه استفاده در صفحات وب:, نمونه متن Sample:
### Community 214 - ".findAll"
Cohesion: 0.32
Nodes (6): ApiNotFoundResponse, ApiOkResponse, ApiOperation, Get, Param, Query
### Community 214 - "BlogsController"
Cohesion: 0.21
Nodes (9): BlogsController, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Param (+1 more)
### Community 215 - "System Discovery"
Cohesion: 0.25
@ -960,49 +966,29 @@ Nodes (3): Expanding the ESLint configuration, React Compiler, React + TypeScrip
Cohesion: 0.50
Nodes (3): Deploy on Vercel, Getting Started, Learn More
### Community 284 - "wholesale.controller.ts"
Cohesion: 0.31
Nodes (6): ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, WholesaleApplyDto
### Community 285 - "InitiatePaymentDto"
Cohesion: 0.43
Nodes (7): InitiatePaymentDto, InitiateWalletTopupDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString
### Community 286 - "GetProductsDto"
Cohesion: 0.29
Nodes (6): GetProductsDto, ApiPropertyOptional, IsEnum, IsOptional, IsString, Query
### Community 287 - "Coupons.tsx"
Cohesion: 0.25
Nodes (5): Coupon, CouponFormData, CouponModalProps, CouponTarget, Coupons
### Community 288 - "SmsSettingsPage.tsx"
Cohesion: 0.29
Nodes (5): PatternItem, SmsConfigState, SmsLogItem, SmsLogStats, SmsSettingsPage
### Community 289 - "ZibalCallbackQueryDto"
Cohesion: 0.40
Nodes (4): ApiPropertyOptional, IsOptional, IsString, ZibalCallbackQueryDto
## Knowledge Gaps
- **1181 isolated node(s):** `$schema`, `collection`, `sourceRoot`, `deleteOutDir`, `name` (+1176 more)
- **1182 isolated node(s):** `$schema`, `collection`, `sourceRoot`, `deleteOutDir`, `name` (+1177 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **113 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
- **114 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `ApiResponse` connect `src/services/api.ts` to `pets/pets.controller.ts`, `UsersService`, `OrdersService`, `admin.ts`, `auth.controller.ts`, `BlogsController`, `ProductsService`, `Home Data Module`, `WikiController`?**
_High betweenness centrality (0.039) - this node is a cross-community bridge._
- **Why does `Roles()` connect `Roles` to `PaymentController`, `JwtAuthGuard`, `CmsController`, `BannersService`, `WholesaleService`, `ProductsService`, `B2B Inquiry Controller`, `wholesale.controller.ts`, `Ingredient Management Controller`, `Prescription Review Controller`, `Smart Advisor Controller`, `Testimonials Management Controller`?**
_High betweenness centrality (0.029) - this node is a cross-community bridge._
- **Why does `PrismaService` connect `PrismaService` to `pets/pets.controller.ts`, `JwtAuthGuard`, `Roles`, `CmsController`, `BannersService`, `UsersService`, `app.module.ts`, `CreateVideoDto`, `ZibalService`, `ProductsService`, `MetricsController`, `B2B Inquiry Controller`, `CategoriesController`, `RedisService`, `MediaController`, `Ingredient Management Controller`, `admin.module.ts`, `Prescription Review Controller`, `Smart Advisor Controller`, `Testimonials Management Controller`, `wholesale.controller.ts`, `WholesaleService`, `seo.module.ts`, `Home Data Module`, `WikiController`, `zibal.service.ts`, `OrdersService`, `BlogsController`, `BlogsService`, `WikiService`?**
_High betweenness centrality (0.025) - this node is a cross-community bridge._
- **Why does `ApiResponse` connect `src/services/api.ts` to `pets/pets.controller.ts`, `UsersService`, `OrdersService`, `AuthController`, `ProductsService`, `Home Data Module`, `BlogsController`, `WikiController`?**
_High betweenness centrality (0.041) - this node is a cross-community bridge._
- **Why does `Roles()` connect `Roles` to `ZibalService`, `JwtAuthGuard`, `CmsController`, `ContactService`, `WholesaleService`, `ProductsService`, `B2B Inquiry Controller`, `Ingredient Management Controller`, `Prescription Review Controller`, `Smart Advisor Controller`, `Testimonials Management Controller`?**
_High betweenness centrality (0.034) - this node is a cross-community bridge._
- **Why does `PaginationDto` connect `PaginationDto` to `AdminService`, `pets/pets.controller.ts`, `JwtAuthGuard`, `OrdersService`, `Admin Blog Controller`, `Generic CRUD Controller`, `.findAll`, `ProductsService`, `CategoriesController`, `BlogsController`, `admin.module.ts`, `Pet Management API`, `WikiController`, `videos.controller.ts`?**
_High betweenness centrality (0.024) - this node is a cross-community bridge._
- **What connects `$schema`, `collection`, `sourceRoot` to the rest of the system?**
_1181 weakly-connected nodes found - possible documentation gaps or missing edges._
_1182 weakly-connected nodes found - possible documentation gaps or missing edges._
- **Should `AdminService` be split into smaller, more focused modules?**
_Cohesion score 0.06690140845070422 - nodes in this community are weakly interconnected._
_Cohesion score 0.06414414414414414 - nodes in this community are weakly interconnected._
- **Should `pets/pets.controller.ts` be split into smaller, more focused modules?**
_Cohesion score 0.0528169014084507 - nodes in this community are weakly interconnected._
- **Should `Roles` be split into smaller, more focused modules?**
_Cohesion score 0.051446321102698506 - nodes in this community are weakly interconnected._
_Cohesion score 0.06347340581839553 - nodes in this community are weakly interconnected._

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"nodes": [{"id": "$graphify-root$_agents_rules_graphify_md", "label": "graphify.md", "file_type": "document", "source_file": ".agents/rules/graphify.md", "source_location": "L1"}, {"id": "$graphify-root$_agents_rules_graphify_graphify", "label": "graphify", "file_type": "document", "source_file": ".agents/rules/graphify.md", "source_location": "L6"}], "edges": [{"source": "$graphify-root$_agents_rules_graphify_md", "target": "$graphify-root$_agents_rules_graphify_graphify", "relation": "contains", "confidence": "EXTRACTED", "source_file": ".agents/rules/graphify.md", "source_location": "L6", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}

View File

@ -0,0 +1 @@
{"nodes": [{"id": "$graphify-root$_claude_md", "label": "CLAUDE.md", "file_type": "document", "source_file": "CLAUDE.md", "source_location": "L1"}, {"id": "$graphify-root$_claude_graphify", "label": "graphify", "file_type": "document", "source_file": "CLAUDE.md", "source_location": "L1"}], "edges": [{"source": "$graphify-root$_claude_md", "target": "$graphify-root$_claude_graphify", "relation": "contains", "confidence": "EXTRACTED", "source_file": "CLAUDE.md", "source_location": "L1", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}

View File

@ -0,0 +1 @@
{"nodes": [{"id": "$graphify-root$_antigravity_instructions_md", "label": "instructions.md", "file_type": "document", "source_file": ".antigravity/instructions.md", "source_location": "L1"}, {"id": "$graphify-root$_antigravity_instructions_graphify", "label": "graphify", "file_type": "document", "source_file": ".antigravity/instructions.md", "source_location": "L1"}], "edges": [{"source": "$graphify-root$_antigravity_instructions_md", "target": "$graphify-root$_antigravity_instructions_graphify", "relation": "contains", "confidence": "EXTRACTED", "source_file": ".antigravity/instructions.md", "source_location": "L1", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}

View File

@ -0,0 +1 @@
{"nodes": [{"id": "$graphify-root$_agents_workflows_graphify_md", "label": "graphify.md", "file_type": "document", "source_file": ".agents/workflows/graphify.md", "source_location": "L1"}, {"id": "$graphify-root$_agents_workflows_graphify_workflow_graphify", "label": "Workflow: graphify", "file_type": "document", "source_file": ".agents/workflows/graphify.md", "source_location": "L6"}], "edges": [{"source": "$graphify-root$_agents_workflows_graphify_md", "target": "$graphify-root$_agents_workflows_graphify_workflow_graphify", "relation": "contains", "confidence": "EXTRACTED", "source_file": ".agents/workflows/graphify.md", "source_location": "L6", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}

View File

@ -0,0 +1 @@
{"nodes": [{"id": "$graphify-root$_claude_claude_md", "label": "CLAUDE.md", "file_type": "document", "source_file": ".claude/CLAUDE.md", "source_location": "L1"}, {"id": "$graphify-root$_claude_claude_graphify", "label": "graphify", "file_type": "document", "source_file": ".claude/CLAUDE.md", "source_location": "L1"}], "edges": [{"source": "$graphify-root$_claude_claude_md", "target": "$graphify-root$_claude_claude_graphify", "relation": "contains", "confidence": "EXTRACTED", "source_file": ".claude/CLAUDE.md", "source_location": "L1", "weight": 1.0}], "input_tokens": 0, "output_tokens": 0}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,9 @@ services:
dockerfile: Dockerfile
container_name: canino_backend_stage
restart: always
dns:
- 217.218.127.127
- 217.218.155.155
environment:
- DATABASE_URL=postgresql://canino_stage:caninopassword_stage@db_stage:5432/caninodb_stage?schema=public
- REDIS_HOST=redis_stage
@ -56,6 +59,9 @@ services:
VITE_API_URL: "https://stageapi.canina.ir"
container_name: canino_frontend_stage
restart: always
dns:
- 217.218.127.127
- 217.218.155.155
labels:
- "traefik.enable=true"
- "traefik.http.routers.canina-stage.rule=Host(`stage.canina.ir`) || Host(`stageadmin.canina.ir`)"