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:
| File | Size | Purpose |
|---|---|---|
types.ts | 4,636 lines | All entity types, LocalizedText, request/response types, enums |
constants.ts | 794 lines | Centralized enum definitions, status mappings, option lists |
money.ts | 227 lines | Decimal money arithmetic via Big.js (fromString, add, round, …) |
decimal.ts | — | Generic decimal-string helpers |
api-types.ts | 95 lines | ApiError, ApiResponse<T>, QueryError, PaginatedResponse<T> |
validation-constants.ts | 39 lines | Field length limits, shared validation rules |
billing-types.ts, billing/ | — | Billing DTOs, recipient address, standalone invoice schema |
party-types.ts | — | Contact/company party types |
value-objects/Email.ts | — | Email value object |
lib/sanitize.ts | — | HTML sanitization utilities (shared between FE/BE) |
lib/localized.ts | — | LocalizedText 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
pgEnumdefinitions - 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:
| Level | Tags Allowed | Use Case |
|---|---|---|
STRICT | None (strips all HTML) | 99% of user input |
BASIC_FORMATTING | <b>, <i>, <em>, <strong>, <br> | Rich text preview |
RICH_TEXT | Extended set | Admin-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, …).
Related Pages
- Backend Architecture — Consumes types for service layer
- Frontend Architecture — Consumes types for components and API clients
- Database Architecture — Entity types mirror schema tables
- Validation Pattern — Zod schemas using shared constants
- API Layer Pattern — API response types
- Error Handling Pattern — Error type definitions
- Coding Guidelines — LocalizedText and naming conventions
- Internationalization — Bilingual text handling