Skip to main content

Synthetics Coding Standards

This guide covers coding standards specific to the Statux Synthetics application.

Service Patterns

Check Validation

Always validate check targets based on type:

// TCP checks require host:port format
if (dto.checkType === CheckType.TCP) {
if (!dto.target.includes(':')) {
throw new BadRequestException('TCP target must be in host:port format');
}
}

// HTTP/HTTPS checks require valid URL
try {
new URL(dto.target);
} catch {
throw new BadRequestException('Invalid URL format');
}

State Updates

Use threshold-based state transitions:

// Check state updates
if (status === CheckStatus.UP) {
check.consecutiveSuccesses++;
check.consecutiveFailures = 0;

if (previousStatus !== CheckStatus.UP &&
check.consecutiveSuccesses >= check.recoveryThreshold) {
check.currentStatus = CheckStatus.UP;
check.lastStatusChangeAt = new Date();
// Fire webhook
}
}

Relay Token Handling

  • Never log raw tokens - only log the prefix
  • Store tokens as SHA-256 hashes
  • Return raw token only once on creation
const rawToken = `stx_relay_${randomBytes(32).toString('hex')}`;
const tokenHash = createHash('sha256').update(rawToken).digest('hex');
const tokenPrefix = rawToken.substring(0, 12);

// Log safely
this.logger.log(`Relay created with token prefix: ${tokenPrefix}`);

Controller Patterns

Guard Usage

All authenticated endpoints should use:

@UseGuards(JwtAuthGuard, ProjectAccessGuard)
@Controller('projects/:projectId/checks')
export class ChecksController {
// ...
}

Relay endpoints use RelayAuthGuard:

@UseGuards(RelayAuthGuard)
@Controller('relay')
export class RelayController {
// ...
}

Parameter Extraction

Use decorators consistently:

@Get(':id')
findOne(
@CurrentProject() project: Project,
@Param('id') id: string,
): Promise<Check> {
return this.checksService.findOne(project.id, id);
}

DTO Patterns

Check DTOs

export class CreateCheckDto {
@IsString()
@MinLength(1)
@MaxLength(255)
name: string;

@IsEnum(CheckType)
checkType: CheckType;

@IsString()
target: string;

@IsEnum(CheckInterval)
intervalSeconds: number;

@IsOptional()
@IsUUID()
relayId?: string;

@IsOptional()
@IsArray()
@IsString({ each: true })
regions?: string[];
}

Result Submission DTOs

export class SubmitResultDto {
@IsUUID()
checkId: string;

@IsEnum(CheckStatus)
status: CheckStatus;

@IsInt()
@Min(0)
responseTimeMs: number;

@IsOptional()
@IsInt()
statusCode?: number;

@IsOptional()
@IsString()
errorMessage?: string;

@IsDateString()
executedAt: string;
}

Testing Standards

Mock Setup

const mockCheck: Partial<Check> = {
id: 'check-1',
projectId: 'proj-1',
name: 'API Health Check',
checkType: CheckType.HTTPS,
target: 'https://api.example.com/health',
currentStatus: CheckStatus.UP,
isEnabled: true,
};

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
ChecksService,
{
provide: getRepositoryToken(Check),
useValue: {
findOne: jest.fn(),
create: jest.fn(),
save: jest.fn(),
// ...
},
},
],
}).compile();
});

Test Categories

  1. CRUD operations: Create, read, update, delete
  2. Validation: Target format, required fields
  3. State transitions: Up/down/degraded logic
  4. Edge cases: Relay assignment, region defaults

Error Handling

Use standard NestJS exceptions:

throw new NotFoundException('Check not found');
throw new BadRequestException('Invalid target format');
throw new ForbiddenException('Check belongs to different relay');

Logging

Use the Logger service consistently:

private readonly logger = new Logger(ChecksService.name);

// Log significant operations
this.logger.log(`Check created: ${check.id} (${check.name})`);
this.logger.warn(`Relay ${relay.id} disconnected`);
this.logger.debug(`Processing ${results.length} results`);