PR Summary

What problems was I solving

Customers need brand-accurate typography using licensed/self-hosted fonts not available through Google Fonts. This PR adds end-to-end support for custom, non-Google brand fonts so tenants can upload their own font files, manage font families and faces with license attestation, assign brands to body/heading/mono roles, and have page-ui serve uploaded fonts via stable /fonts/{tenantId}/{brandId}/{faceId}.{ext} URLs.

What user-facing changes did I ship

Adds Brand Fonts panel to the Brand Details workspace in the management UI where users can: create uploaded font families with aliases/attestation, request and complete face uploads with WOFF/WOFF2 files, assign uploaded/google/system fonts to body/heading/mono roles, view font status and face count. Page rendering now loads uploaded fonts via browser preloaded links instead of Google Fonts API and uses Stable CSS variables (--font-sans, --font-heading, --font-mono) in addition to themeTokens.

How I implemented it

The implementation follows the existing modular architecture: brand-service owns the data model and RPC operations (families, faces, assignments, upload sessions) in brand_font_families/brand_font_faces/brand_font_assignments tables; admin-gateway serves 7 HTTP endpoints for font management; management-gateway GraphQL extends with brand-font queries/mutations; management-ui view-model builds typed queries and GraphQL client refactored to support generic requests; brand-rendering-model generates @font-face CSS and preload metadata; page-service fetches brand fonts into RenderingBrandFonts and injects them into page previews and SSR; page-gateway serves stable font assets via /fonts/{tenantId}/{brandId}/{faceId}.{ext} proxy with Cache-Control immutable headers.

Description for the changelog

Adds non-Google brand font support: brand_service gains font families, faces, aliases, assignments, and upload sessions tables with strict row-level constraints; brand-service-api exposes RPC-safe font management methods; admin-gateway adds /font-families, /font-assignments HTTP endpoints; management-gateway GraphQL includes brand-font queries/mutations; management-ui adds BrandFontsPanel workflow with license attestation and face upload; page-ui rendering now emits @font-face CSS and preload links for uploaded fonts; page-service projects brand.fonts into RenderingBrand rendering model; page-gateway adds stable font serving proxy. Backwards compatible: brand.fonts is optional, legacy Google-font detection continues to work, customCss-based font extraction is unaffected.

Brand font database schema and migrations

high4 files
Adds brand-font entities (families, faces, aliases, assignments, upload sessions) to brand_service schema with strict row-level constraints on source fields, license attestation, weight/variable ranges, and tenant/brand isolation.

Brand font RPC API contracts

medium3 files
Adds RPC-safe brand-font API feature (List/Create/Disable service methods plus face upload-session management) to brand-service-api with strict Zod schemas, TypeID enforcement, and license attestation validation.

Brand font GraphQL boundary for management UI

medium2 files
Extends ManagementGateway GraphQL schema with brand-font queries/mutations (list families/assignments, create/disable family/request/complete face upload, update assignments) while keeping admin tRPC unchanged.

Brand font HTTP admin API endpoints

medium4 files
Registers 7 brand-font HTTP endpoints (/font-families, /font-families/uploaded, /font-families/:familyId, /font-families/:familyId/faces/uploads, /font-face-uploads/:uploadSessionId/faces/:faceId/complete, /font-assignments) with endpoint-specific path params, OpenAPI spec generation, and zod request/response handling.

Brand font rendering output contracts

medium5 files
Firmly defines RenderingBrandFonts output contract (generatedCss, families, assignments, preloadFaces) used by page-ui rendering model and page-rendering-react runtime for @font-face CSS and browser preloading.

Page service brand-font projection feature

medium4 files
Transforms canonical Brand to RenderingBrand with `brand.fonts` populated by fetching font assignments/families (in parallel), logging warnings for unassigned uploaded families, and injecting brand-service into PageResolvedConfigFeature.

Page gateway brand-font stable serving proxy

medium4 files
Adds stable font serving endpoint at /fonts/{tenantId}/{brandId}/{faceId}.{ext}, injects BrandService RPC client, validates tenant/brand/face ownership + status, and returns public Cache-Control headers for immutable assets.

Brand font admin API OpenAPI specification

medium
Expands OpenAPI schema to include 7 brand-font endpoints (list families, create uploaded, disable, request/complete face uploads, get/update assignments) with request/response models generated from zod schemas.

Brand font data access repository

low2 files
Implements full-brand-font CRUD, upload lifecycle management, and assignment projection via Sapatos with deferred bigint internal conversion and aliases/faces eager-loading.

Brand service implementation with font operations

low2 files
Attaches brand-font RPC methods to BrandServiceImpl (request upload/complete upload/create family/disable/upsert assignments) with file-service integration, validation pipeline, and squash-plan tracking.

Brand font CSS builder and projected typography engine

low4 files
Generates deterministic @font-face CSS strings and CSS variables for page-ui by projecting brand-service assignments into RenderingBrandFonts, filtering only assigned active faces, escaping CSS strings/URLs, and emitting stable font-preload metadata.

Management UI brand-font GraphQL operations and view-model

low5 files
Implements brand-font GraphQL queries (BrandFontFamilies, BrandFontAssignments) and generic management GraphQL request handler, typed with strict Zod schemas and stable query keys for react-query consumption.

Brand font management UI panel and wireframe

low3 files
Adds BrandFontsPanel control surface with create family/face upload wizard and assignment controls, plus inline UI guidance for restricted-font selection in font-picker tiles.

Brand font CSS builder tests

low
Tests brand font CSS generation (escaping, font-face rule construction, assignment variable emission) and RenderingBrandFonts projection for uploaded/google/system fonts.

Page rendering React runtime tests

low2 files
Tests dynamic font loader, brand font stylesheet link/render/preload generation, page-preview integration, and backward compatibility when brand.fonts is null or upload-only (no Google request).

Brand font feature integration tests

low
Tests page-service's brand-font projection orchestration (fetching assignments/families in parallel), rendering integration via BrandRenderingFeature, and PageResolvedConfigFeature injection including service method mocks.

Brand service implementation integration tests

low
Adds brand font validation tests (ext/content type mismatch, inverted variable range) to existing brand-service integration tests and adds infoMock to logger.

Generic GraphQL request handler infrastructure

low1 file
Refactors GraphQL client to split raw fetch retry logic (managementGraphqlRawRequest) from typed document wrapper (managementGraphqlRequest), enabling generic requests for all view-model operations including brand-fonts.

Other changes in architect/page-rendering-react

low3 files
3 changed files not fully analyzed by the agent.

Other changes in architect/services

low3 files
3 changed files not fully analyzed by the agent.

Other changes in architect/tmp

low1 file
1 changed file not fully analyzed by the agent.