Shared Layer

The renewa-one/shared/ directory contains cross-cutting types, constants, and utilities consumed by both backend and frontend.

Files

Sizes as of 2026-06:

FileSizePurpose
types.ts4,636 linesAll entity types, LocalizedText, request/response types, enums
constants.ts794 linesCentralized enum definitions, status mappings, option lists
money.ts227 linesDecimal money arithmetic via Big.js (fromString, add, round, …)
decimal.tsGeneric decimal-string helpers
api-types.ts95 linesApiError, ApiResponse<T>, QueryError, PaginatedResponse<T>
validation-constants.ts39 linesField length limits, shared validation rules
billing-types.ts, billing/Billing DTOs, recipient address, standalone invoice schema
party-types.tsContact/company party types
value-objects/Email.tsEmail value object
lib/sanitize.tsHTML sanitization utilities (shared between FE/BE)
lib/localized.tsLocalizedText helpers

money.ts (MANDATORY for money values)

decimal(p, s) columns leave Drizzle as strings; coercing to JS number drifts and breaks billing (spec docs/superpowers/specs/2026-04-24-money-arithmetic-bigjs-design.md). Parse at the boundary with fromString(...), compute via add/sub/mul/div + round(m, 2) (HALF_UP), stringify back with toString. Money is always a decimal string on the wire — never number in DTOs. Enforced by quick-lint.sh, the renewa-local/no-number-on-money ESLint rule, and /audit.

types.ts

The single source of truth for all TypeScript types across the application. Every entity in Database Architecture has a corresponding type here.

Key type categories:

  • Entity types: Project, Building, Scenario, Contact, Company, Lead, Quote, Invoice, etc.
  • LocalizedText: { de: string; en: string } — used for all bilingual database fields
  • Enums: TypeScript enum types mirroring PostgreSQL pgEnum definitions
  • Request/Response: Typed API payloads for each endpoint
  • Utility types: Nullable<T>, WithTimestamps, WithAuditFields

constants.ts

Centralized enum values and option definitions. Used by both frontend (dropdowns, filters) and backend (validation).

Includes: status enums, role definitions, building type options, energy source types, document categories, and more.

api-types.ts

Shared API contract types:

interface ApiResponse<T> { data: T; message?: string; }
interface ApiError { error: string; details?: unknown; statusCode: number; }
interface QueryError { message: string; statusCode: number; }
interface PaginatedResponse<T> { data: T[]; total: number; page: number; pageSize: number; }

Used by frontend API clients and backend error handlers.

validation-constants.ts

Field length limits shared between frontend form validation and backend Zod schemas:

export const FIELD_LENGTHS = {
  SHORT_TEXT: 100,
  MEDIUM_TEXT: 255,
  LONG_TEXT: 1000,
  // ...
};

Consumed by Validation Pattern helpers like sanitizedLocalizedText(maxLength).

lib/sanitize.ts

HTML sanitization using DOMPurify. Three levels:

LevelTags AllowedUse Case
STRICTNone (strips all HTML)99% of user input
BASIC_FORMATTING<b>, <i>, <em>, <strong>, <br>Rich text preview
RICH_TEXTExtended setAdmin-only content, never user input

See Validation Pattern for sanitization integration with Zod schemas.

Package Configuration

The shared package is referenced via TypeScript path aliases in both backend/ and frontend/ tsconfigs:

{ "paths": { "@shared/*": ["../shared/*"] } }

No separate build step — consumed directly as TypeScript source. Tests are co-located (money.test.ts, constants.test.ts, …).