NJ Municipality Lookup
CodebaseSrcDomain

Entities

Core business objects representing key concepts in the application domain. All entities are immutable and validated upon creation.

Domain Entities (domain/entities/)

Core business objects representing key concepts in the application domain. All entities are immutable and validated upon creation.

Why Entities Exist

Entities encapsulate the core business concepts:

  • Type safety: Branded types prevent mixing up strings at compile time
  • Validation: All inputs validated before entity creation
  • Immutability: Entities can't be accidentally modified
  • Self-documenting: Entity structure describes the domain

Entities

municipality.ts

Represents a New Jersey municipality name using branded types for compile-time safety.

export type MunicipalityName = Brand<string, "MunicipalityName">;
export const createMunicipalityName = (name: string): MunicipalityName

Validation: Non-empty, trimmed strings

address.ts

Validated user address input with normalization and security validation.

export type AddressInput = Brand<string, "AddressInput">;
export const createAddressInput = (text: string): AddressInput

Features:

  • Unicode normalization (NFC)
  • Whitespace normalization
  • XSS protection (rejects HTML/JavaScript patterns)
  • Length limits (max 500 characters)

geocoding-result.ts

Geocoding response including location, municipality, and metadata.

export interface GeocodingResult {
  inputAddress: AddressInput;
  formattedAddress: string;
  municipality: MunicipalityName;
  coordinates: { latitude: number; longitude: number };
  components?: AddressComponents;
  score: number;
  fromCache: boolean;
}

Factory: createGeocodingResult() with validation

cache-entry.ts

Cache storage structure with TTL and expiration tracking.

export interface CacheEntry<T> {
  key: string;
  value: T;
  createdAt: number;
  expiresAt: number;
  accessCount: number;
  lastAccessed: number;
}

Features:

  • Automatic expiration calculation
  • Access tracking for LFU eviction
  • Immutable after creation

bulk-job.ts

Batch address geocoding operation with progress tracking and result management.

export interface BulkJob {
  id: string;
  addresses: readonly string[];
  status: BulkJobStatus;
  results: BulkAddressResult[];
  successCount: number;
  errorCount: number;
  createdAt: string;
  startedAt?: string;
  completedAt?: string;
  processingTimeMs?: number;
}

export type BulkJobStatus = "pending" | "processing" | "completed" | "failed";

Features:

  • Process up to 1,000 addresses per job
  • Per-address success/error tracking
  • State machine: pending → processing → completed/failed
  • Processing time metrics

Factory functions: createBulkJob(), startBulkJob(), completeBulkJob(), addBulkJobResult()

health-status.ts

System health monitoring for operational dashboards and alerting.

export interface HealthStatus {
  state: HealthState;
  components: readonly ComponentHealth[];
  uptimeMs: number;
  timestamp: string;
}

export type HealthState = "healthy" | "degraded" | "unhealthy";
export type HealthComponent =
  | "application"
  | "cache"
  | "nj-suggestions-api"
  | "nj-geocoding-api";

Features:

  • Three-state health model (healthy/degraded/unhealthy)
  • Component-level health tracking
  • Response time and error capture
  • Worst-state aggregation for overall health

Factory functions: createComponentHealth(), createHealthStatus()

Patterns

Branded Types

All entities use branded types to prevent string confusion at compile time:

const munName: MunicipalityName = createMunicipalityName("Newark");
const address: AddressInput = createAddressInput("123 Main St");

// Compile error: Type 'AddressInput' is not assignable to type 'MunicipalityName'
const wrong: MunicipalityName = address; //

Factory Functions

Entities are created through factory functions that validate inputs:

createAddressInput("valid address"); //Returns AddressInput
createAddressInput("<script>alert()</script>"); //Throws ValidationError

Immutability

All entities are read-only. Modifications create new instances:

const entry = createCacheEntry("key", value, 7);
// entry.key = "new"; // ❌ Compile error: readonly property

Testing

Each entity has unit tests covering:

  • Valid creation scenarios
  • Validation edge cases
  • Error conditions
  • Serialization (toJSON)
  • Type guards and invariants

On this page