osac-ux

osac-ui

Web console for the Open Sovereign AI Cloud (OSAC) project — a self-service platform for deploying OpenShift clusters, virtual machines, and bare metal hosts. pnpm monorepo with React 19 + PatternFly 6 (frontend) and a Go chi reverse proxy (BFF with OIDC authentication).

Critical Rules

Dev Environment

Prerequisites: Node.js 20+, pnpm 9+, Go 1.23+

pnpm install                   # Install dependencies

# Start development servers
FULFILLMENT_API_URL=https://... pnpm dev    # Go proxy and Vite on :5173

# Build
pnpm build                     # TypeScript check + Vite build + Go binary

# Test
pnpm test                      # Vitest unit tests
pnpm e2e:ci                    # Cypress E2E tests

# Lint and format
pnpm lint                      # ESLint + Prettier + i18n sync check
pnpm format                    # Prettier write

# Type generation
pnpm gen-types                 # Regenerate TS types from protobuf

# Translations
pnpm i18n                      # Extract t() keys and update libs/i18n/locales/en/translation.json

# Validate PatternFly usage
pnpm check:pf-primitives

# Regenerate API diff manifest (also runs automatically on postinstall)
pnpm gen:api-diff

# Container build
podman build -t osac:latest -f Containerfile .

Repository Structure

osac-ui/
├── apps/
│   ├── app-frontend/          # React 19 SPA (Vite + TypeScript + PatternFly 6)
│   └── e2e/                   # Cypress end-to-end tests
├── libs/
│   ├── i18n/                  # Translation extraction config + generated locale files
│   ├── api-contracts/         # Shared TS types + wire normalizers
│   ├── types/                 # Generated types from protobuf (do not edit)
│   └── ui-components/         # Shared PatternFly 6 component library
├── proxy/                     # Go chi reverse proxy (OIDC auth + API forwarding)
├── deploy/
│   └── chart/                 # Helm chart for Kubernetes deployment
├── docs/
│   ├── specs/                 # Feature specs, statecharts, flow definitions
│   └── runbook.md             # Development and deployment instructions
├── scripts/                   # Helper scripts (PF validation, statechart graphs)
└── pnpm-workspace.yaml        # Workspace: apps/*, libs/*

Workspace Packages

Package Purpose
@osac/app-frontend React SPA — Vite, React 19, TanStack Query, react-router-dom 7
@osac/e2e Cypress E2E tests
@osac/i18n Translation extraction config (i18next.config.ts) + generated locale files
@osac/api-contracts Shared TS types + wire normalizers (single source of truth for API types)
@osac/types Generated protobuf types (do not edit)
@osac/ui-components Shared PatternFly 6 components (consumed at source, no build step)

Code Style

TypeScript and React

Styling

  1. Prefer PatternFly CSS classes and utility classes
  2. Avoid custom CSS files for routine UI — stay within PatternFly’s supported customization paths
  3. Never replace PatternFly tokens with arbitrary colors, spacing, or typography
  4. Avoid inline styles (style=) except for dynamic values that cannot be expressed in CSS

UI and Accessibility

React Performance and memo

Treat memoization as an optimization, not a correctness tool:

Internationalization (i18n)

The app uses i18next + react-i18next with English string keys (the English text itself is the key). Translation files are generated by scanning source code for t() calls and <Trans> components.

Generated file — do not edit by hand

libs/i18n/locales/en/translation.json is the single source of truth for translations. It is generated by i18next-cli and must not be edited manually. Update it by modifying source strings and running:

pnpm i18n

Commit the updated translation.json alongside the source changes. pnpm lint runs the same check in CI mode (--ci) and fails if the file is out of sync with the source.

Using translations in components

Always import useTranslation from @osac/ui-components/hooks/useTranslation — never directly from react-i18next. ESLint enforces this.

import { useTranslation } from '@osac/ui-components/hooks/useTranslation';

const MyComponent = () => {
  const { t } = useTranslation();
  return <h1>{t('Page title')}</h1>;
};

For pure (non-component) utilities that need translations, accept t: TFunction as a parameter (imported from i18next) and call useTranslation in the component that invokes them:

import type { TFunction } from 'i18next';

export const getLabels = (t: TFunction) => ({
  save: t('Save'),
  cancel: t('Cancel'),
});

Rules

Translation files at runtime

vite-plugin-static-copy copies libs/i18n/locales/ into the Vite build output (dist/locales/). The Go proxy serves these as static files. The i18next HTTP backend loads them at runtime from /locales//.json.

Test

Specs and Traceability

Quality Bar

Security

Go Proxy

The Go reverse proxy handles OIDC authentication and forwards API requests to the fulfillment service.

Env Var Required Description
FULFILLMENT_API_URL Yes Upstream API base URL
PORT No Listen port (default: 8080)
HOST No Listen host (default: 0.0.0.0)
BASE_UI_URL No Public base URL of the UI — used to compute the /callback redirect URI; derived from the SPA’s redirect_base query parameter if unset
OIDC_CLIENT_ID No OIDC client ID (default: osac-ui)
OIDC_TLS_CA_FILE No Custom CA bundle for the OIDC IdP
OIDC_TLS_INSECURE No Skip TLS verification for the OIDC IdP (dev only)
FULFILLMENT_TLS_CA_FILE No Custom CA bundle for the fulfillment service
FULFILLMENT_TLS_INSECURE No Skip TLS verification for the fulfillment service (dev only)

Proxied paths: /api/fulfillment/v1/*, /api/events/v1/*, /api/osac/public/v1/*

CI

GitHub Actions (.github/workflows/):

Documentation

Area Location
Feature specs and acceptance criteria docs/specs/
Statechart definitions (XState) docs/specs/statecharts/
Development and deployment runbook docs/runbook.md