Rebrand product to Hesychia (hesychia.ai) (#29)
Unit Tests / test (pull_request) Successful in 10s

Rename user-facing UI, page metadata, and docs from the AIML Operations chat
product to Hesychia. Keep live API hosts and deploy webroots; document the
hesychia.ai migration path until infra cutover.
This commit is contained in:
2026-07-26 18:33:25 -05:00
parent 3162ed1f7f
commit d11a97b9bf
12 changed files with 55 additions and 28 deletions
+31 -12
View File
@@ -1,7 +1,9 @@
# Chat Web App (`chat_web_app`) # Hesychia (`chat_web_app`)
Frontend for [chat.aimloperations.com](https://chat.aimloperations.com) — a React + Frontend for **[Hesychia](https://hesychia.ai)** — a React + TypeScript single-page
TypeScript single-page app for the AI ML Operations chat product. app for a calm AI assistant experience (quiet, rest, stillness).
Public product domain: **hesychia.ai** (replacing `chat.aimloperations.com`).
Companion backend: [chat_backend](https://git.aimloperations.com/ai_ml_operations/chat_backend) Companion backend: [chat_backend](https://git.aimloperations.com/ai_ml_operations/chat_backend)
@@ -10,13 +12,29 @@ document root; the shared **web-static** nginx container from
[server-infra](https://git.aimloperations.com/ai_ml_operations/server-infra) serves [server-infra](https://git.aimloperations.com/ai_ml_operations/server-infra) serves
those assets. Same pattern as `dta_webapp`. those assets. Same pattern as `dta_webapp`.
Android Capacitor shell (display name **Hesychia**) lands via the Capacitor wrap
PR; branding strings there use Hesychia once that tree is on `master`.
## Domain migration
| Role | Current (still live) | Target |
|------|----------------------|--------|
| Web UI | `chat.aimloperations.com` | `hesychia.ai` |
| REST / WS API | `chatbackend.aimloperations.com` | TBD under hesychia.ai (infra cutover) |
| Deploy webroot | `/var/www/{env}.chat.aimloperations/html` | Keep until `server-infra` renames |
Committed `.env.production` / `.env.beta` still point at the **current**
`*.aimloperations.com` API hosts so builds keep working. Flip those URLs (and
deploy webroots / NPM) when DNS and `server-infra` cut over to hesychia.ai.
## Stack ## Stack
- **React 18**, **TypeScript**, **Create React App** (`react-scripts` 5) - **React 18**, **TypeScript**, **Create React App** (`react-scripts` 5)
- **Material UI (MUI) 5** + Emotion for components and theming - **Material UI (MUI) 5** + Emotion for components and theming
- **React Router 6** for routing - **React Router 6** for routing (`BrowserRouter` on web; `HashRouter` under Capacitor)
- **Axios** for REST against `chat_backend` - **Axios** for REST against `chat_backend` (JWT `Authorization` header)
- **WebSocket** for live chat (`REACT_APP_BACKEND_WS_API_BASE_URL`) - **WebSocket** for live chat (`REACT_APP_BACKEND_WS_API_BASE_URL`)
- **Capacitor 7** for Android (and later iOS) WebView shells
- **Jest** + React Testing Library for unit tests - **Jest** + React Testing Library for unit tests
## Repository layout ## Repository layout
@@ -25,20 +43,21 @@ those assets. Same pattern as `dta_webapp`.
chat_web_app/ chat_web_app/
├── README.md ├── README.md
├── .gitea/workflows/ # Unit tests + deploy-prod / deploy-beta ├── .gitea/workflows/ # Unit tests + deploy-prod / deploy-beta
└── llm-fe/ # CRA application (npm root) └── llm-fe/ # CRA npm root (+ Capacitor when Android wrap merges)
├── package.json ├── package.json
├── .env.development # Local dev API/WS URLs ├── .env.development # Local dev API/WS URLs
├── .env.beta ├── .env.beta
├── .env.production ├── .env.production
├── public/ ├── public/
└── src/ └── src/
├── axiosApi.js # Axios instances (JWT + CSRF) ├── axiosApi.js # Axios instances (JWT Authorization)
├── App.tsx ├── App.tsx
├── index.tsx ├── index.tsx
└── llm-fe/ └── llm-fe/
├── pages/ # Route-level views ├── pages/ # Route-level views
├── components/ # Shared & feature UI ├── components/ # Shared & feature UI
├── contexts/ # Auth, account, WebSocket, theme ├── contexts/ # Auth, account, WebSocket, theme
├── platform/ # Capacitor routing / native chrome
└── ui-kit/ # MD* design-system wrappers └── ui-kit/ # MD* design-system wrappers
``` ```
@@ -48,6 +67,7 @@ chat_web_app/
- **npm** (lockfile: `llm-fe/package-lock.json`) - **npm** (lockfile: `llm-fe/package-lock.json`)
- Running [chat_backend](https://git.aimloperations.com/ai_ml_operations/chat_backend) - Running [chat_backend](https://git.aimloperations.com/ai_ml_operations/chat_backend)
locally for full chat/auth (default in `.env.development`: port **8001**) locally for full chat/auth (default in `.env.development`: port **8001**)
- For Android (after Capacitor wrap merges): JDK 17+, Android Studio / SDK
## Local setup ## Local setup
@@ -64,12 +84,11 @@ npm ci
CRA loads mode-specific env files. Variables must be prefixed with `REACT_APP_` CRA loads mode-specific env files. Variables must be prefixed with `REACT_APP_`
to be visible in the browser bundle. to be visible in the browser bundle.
| File | Used when | Backend | | File | Used when | Backend (current) |
|------|-----------|---------| |------|-----------|-------------------|
| `.env.development` | `npm start` | `http://127.0.0.1:8001` | | `.env.development` | `npm start` | `http://127.0.0.1:8001` |
| `.env.production` | `npm run build` / `build:prod` | `https://chatbackend.aimloperations.com` | | `.env.production` | `npm run build` / `build:prod` | `https://chatbackend.aimloperations.com` |
| `.env.beta` | `npm run build:beta` | `https://beta.chatbackend.aimloperations.com` | | `.env.beta` | `npm run build:beta` | `https://beta.chatbackend.aimloperations.com` |
Required keys (already set in the committed env files): Required keys (already set in the committed env files):
```env ```env
@@ -116,7 +135,7 @@ Open **http://localhost:3000**.
`build:prod` / `build:beta` are intended for deploy hosts (or a machine that can `build:prod` / `build:beta` are intended for deploy hosts (or a machine that can
write those `/var/www/...` paths). Paths must match write those `/var/www/...` paths). Paths must match
`server-infra` `app_catalog.chat_web_app.webroot_pattern`: `server-infra` `app_catalog.chat_web_app.webroot_pattern` until renamed:
```text ```text
/var/www/{env}.chat.aimloperations/html /var/www/{env}.chat.aimloperations/html
@@ -154,7 +173,7 @@ Manual deploy from the control node:
--app chat_web_app --env prod --ref <sha> --app chat_web_app --env prod --ref <sha>
``` ```
NPM (not managed by Ansible) should balance public chat domains to: NPM (not managed by Ansible) should balance public Hesychia domains to:
- `adama:8082` + `roslin:8082` + `ai-server-4080:8082` (prod) - `adama:8082` + `roslin:8082` + `ai-server-4080:8082` (prod)
+2
View File
@@ -1,2 +1,4 @@
# Beta API hosts (current). Target public product domain: hesychia.ai
# Flip these to hesychia.ai API hosts when server-infra / DNS cut over.
REACT_APP_BACKEND_REST_API_BASE_URL=https://beta.chatbackend.aimloperations.com/api/ REACT_APP_BACKEND_REST_API_BASE_URL=https://beta.chatbackend.aimloperations.com/api/
REACT_APP_BACKEND_WS_API_BASE_URL=wss://beta.chatbackend.aimloperations.com/ws/chat_again/ REACT_APP_BACKEND_WS_API_BASE_URL=wss://beta.chatbackend.aimloperations.com/ws/chat_again/
+3 -1
View File
@@ -1,2 +1,4 @@
# Production API hosts (current). Target public product domain: hesychia.ai
# Flip these to hesychia.ai API hosts when server-infra / DNS cut over.
REACT_APP_BACKEND_REST_API_BASE_URL=https://chatbackend.aimloperations.com/api/ REACT_APP_BACKEND_REST_API_BASE_URL=https://chatbackend.aimloperations.com/api/
REACT_APP_BACKEND_WS_API_BASE_URL=wss://chatbackend.aimloperations.com/ws/chat_again/ REACT_APP_BACKEND_WS_API_BASE_URL=wss://chatbackend.aimloperations.com/ws/chat_again/
+6 -2
View File
@@ -8,7 +8,11 @@
<link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/favicon-16x16.png" /> <link rel="icon" type="image/png" sizes="16x16" href="%PUBLIC_URL%/favicon-16x16.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta name="description" content="Chat app by AI ML Operations, LLC" /> <meta name="description" content="Hesychia — a calm AI assistant by AI ML Operations, LLC" />
<meta name="application-name" content="Hesychia" />
<meta property="og:title" content="Hesychia" />
<meta property="og:description" content="Hesychia — quiet, focused AI chat at hesychia.ai" />
<meta property="og:url" content="https://hesychia.ai" />
<link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-touch-icon.png" /> <link rel="apple-touch-icon" sizes="180x180" href="%PUBLIC_URL%/apple-touch-icon.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
@@ -24,7 +28,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>Chat by AI ML Operations. LCC</title> <title>Hesychia</title>
</head> </head>
<body> <body>
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"short_name": "Chat by AI ML Operations. LLC", "short_name": "Hesychia",
"name": "Chat by AI ML Operations, LLC", "name": "Hesychia",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "favicon.ico",
@@ -115,7 +115,7 @@ const DashboardWrapperLayout = ({ children }: DashboardWrapperLayoutProps): JSX.
<Sidenav <Sidenav
color={sidenavColor} color={sidenavColor}
brand={(transparentSidenav && !darkMode) || whiteSidenav ? brandDark : brandWhite} brand={(transparentSidenav && !darkMode) || whiteSidenav ? brandDark : brandWhite}
brandName="Chat by AI ML, Operations, LLC" brandName="Hesychia"
routes={[]} // {routes} routes={[]} // {routes}
onMouseEnter={handleOnMouseEnter} onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave} onMouseLeave={handleOnMouseLeave}
@@ -136,7 +136,7 @@ const DashboardWrapperLayout = ({ children }: DashboardWrapperLayoutProps): JSX.
<Sidenav <Sidenav
color={sidenavColor} color={sidenavColor}
brand={(transparentSidenav && !darkMode) || whiteSidenav ? brandDark : brandWhite} brand={(transparentSidenav && !darkMode) || whiteSidenav ? brandDark : brandWhite}
brandName="AI ML, Operations, LLC" brandName="Hesychia"
routes={[]} // {routes} routes={[]} // {routes}
onMouseEnter={handleOnMouseEnter} onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave} onMouseLeave={handleOnMouseLeave}
@@ -11,10 +11,10 @@ describe('Footer', () => {
it('renders copyright and developer credit', () => { it('renders copyright and developer credit', () => {
render(<Footer />); render(<Footer />);
expect(screen.getByText(/© 2025 Chat/i)).toBeInTheDocument(); expect(screen.getByText(/© 2026 Hesychia/i)).toBeInTheDocument();
expect(screen.getByRole('link', { name: /AI ML Operations, LLC/i })).toHaveAttribute( expect(screen.getByRole('link', { name: /AI ML Operations, LLC/i })).toHaveAttribute(
'href', 'href',
'www.aimloperations.com' 'https://www.aimloperations.com'
); );
}); });
}); });
@@ -5,7 +5,7 @@ const Footer = (): JSX.Element => {
return ( return (
<div className='continer-fluid'> <div className='continer-fluid'>
<MDTypography>&copy; 2025 Chat | Developed by <a href='www.aimloperations.com'>AI ML Operations, LLC</a></MDTypography> <MDTypography>&copy; 2026 Hesychia | Developed by <a href='https://www.aimloperations.com'>AI ML Operations, LLC</a></MDTypography>
</div> </div>
); );
@@ -67,7 +67,7 @@ const Header = ({drawerWidth=0, handleDrawerToggle}: HeaderProps): JSX.Element =
{isLargeScreen ? ( {isLargeScreen ? (
<> <>
<Typography variant="h6" style={{ flexGrow: 1 }} className='text-white font-weight-bold'> <Typography variant="h6" style={{ flexGrow: 1 }} className='text-white font-weight-bold'>
Chat | AI Ml Operations Hesychia
</Typography > </Typography >
<Button color="inherit" onClick={handleDashboardClick}> <Button color="inherit" onClick={handleDashboardClick}>
Dashboard</Button> Dashboard</Button>
@@ -81,7 +81,7 @@ const Header = ({drawerWidth=0, handleDrawerToggle}: HeaderProps): JSX.Element =
) : ( ) : (
<> <>
<Typography variant="h6" style={{ flexGrow: 1 }} className='text-white font-weight-bold'> <Typography variant="h6" style={{ flexGrow: 1 }} className='text-white font-weight-bold'>
Chat Hesychia
</Typography > </Typography >
<IconButton color="inherit" onClick={handleDashboardClick}> <IconButton color="inherit" onClick={handleDashboardClick}>
<Dashboard /> <Dashboard />
@@ -150,7 +150,7 @@ const Header2 = ({ absolute = false, light = false, isMini = false }: Header2Pro
return ( return (
<HeaderContainer> <HeaderContainer>
<Logo onClick={() => navigate('/')}> <Logo onClick={() => navigate('/')}>
<h4>Chat</h4> <h4>Hesychia</h4>
</Logo> </Logo>
+2 -2
View File
@@ -57,8 +57,8 @@ const SamplePage: React.FC = () => {
</Container> </Container>
<footer className="footer"> <footer className="footer">
<a href="https://aimloperations.com" target="_blank" rel="noopener noreferrer"> <a href="https://hesychia.ai" target="_blank" rel="noopener noreferrer">
Visit AIMLOperations.com Visit hesychia.ai
</a> </a>
</footer> </footer>
</div> </div>
@@ -36,7 +36,7 @@ const TermsOfService = (): JSX.Element => {
</CardContent> </CardContent>
<Divider /> <Divider />
<MDTypography> <MDTypography>
Welcome to chat.aimloperations.com! We're excited to have you on board. Before you start using our large language model, supplied by AI ML Operations, LLC, we need you to agree to our Terms of Service. Welcome to Hesychia (hesychia.ai)! We're excited to have you on board. Before you start using our large language model, supplied by AI ML Operations, LLC, we need you to agree to our Terms of Service.
</MDTypography> </MDTypography>
<MDTypography variant="h4"> <MDTypography variant="h4">
1. Acceptance of Terms 1. Acceptance of Terms