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

## Summary
- Closes #29
- Rename user-facing product from AIML Operations chat to **Hesychia** (headers, sidenav brand, footer, ToS welcome, sample page)
- Update page metadata (`title`, description, Open Graph, `manifest.json` app name)
- Point README / env comments at **hesychia.ai**; keep live API hosts and deploy webroots until infra cutover

## Android display name
Capacitor tree is not on `master` yet ([#28](#28)). Display name / `appName` → **Hesychia** pushed on `ship-android-capacitor-20` so it lands with that wrap. Package id stays `com.aimloperations.chat` (Play identity; rename later if desired).

## Out of scope (per issue)
- New logo artwork (#30)
- Backend system-prompt identity (`chat_backend` #20)

## Test plan
- [ ] Web UI shows **Hesychia** in header / sidenav / footer (no old product name)
- [ ] Browser tab title and PWA manifest name are Hesychia
- [ ] Footer still credits AI ML Operations, LLC as developer
- [ ] `npm run test:ci` (Footer test updated)
- [ ] After #28 merges: Android launcher / activity title shows HesychiaReviewed-on: #32
This commit was merged in pull request #32.
This commit is contained in:
2026-07-26 17:07:26 -07:00
parent 3162ed1f7f
commit b7f23eb16c
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 +
TypeScript single-page app for the AI ML Operations chat product.
Frontend for **[Hesychia](https://hesychia.ai)** — a React + TypeScript single-page
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)
@@ -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
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
- **React 18**, **TypeScript**, **Create React App** (`react-scripts` 5)
- **Material UI (MUI) 5** + Emotion for components and theming
- **React Router 6** for routing
- **Axios** for REST against `chat_backend`
- **React Router 6** for routing (`BrowserRouter` on web; `HashRouter` under Capacitor)
- **Axios** for REST against `chat_backend` (JWT `Authorization` header)
- **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
## Repository layout
@@ -25,20 +43,21 @@ those assets. Same pattern as `dta_webapp`.
chat_web_app/
├── README.md
├── .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
├── .env.development # Local dev API/WS URLs
├── .env.beta
├── .env.production
├── public/
└── src/
├── axiosApi.js # Axios instances (JWT + CSRF)
├── axiosApi.js # Axios instances (JWT Authorization)
├── App.tsx
├── index.tsx
└── llm-fe/
├── pages/ # Route-level views
├── components/ # Shared & feature UI
├── contexts/ # Auth, account, WebSocket, theme
├── platform/ # Capacitor routing / native chrome
└── ui-kit/ # MD* design-system wrappers
```
@@ -48,6 +67,7 @@ chat_web_app/
- **npm** (lockfile: `llm-fe/package-lock.json`)
- Running [chat_backend](https://git.aimloperations.com/ai_ml_operations/chat_backend)
locally for full chat/auth (default in `.env.development`: port **8001**)
- For Android (after Capacitor wrap merges): JDK 17+, Android Studio / SDK
## Local setup
@@ -64,12 +84,11 @@ npm ci
CRA loads mode-specific env files. Variables must be prefixed with `REACT_APP_`
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.production` | `npm run build` / `build:prod` | `https://chatbackend.aimloperations.com` |
| `.env.beta` | `npm run build:beta` | `https://beta.chatbackend.aimloperations.com` |
Required keys (already set in the committed env files):
```env
@@ -116,7 +135,7 @@ Open **http://localhost:3000**.
`build:prod` / `build:beta` are intended for deploy hosts (or a machine that can
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
/var/www/{env}.chat.aimloperations/html
@@ -154,7 +173,7 @@ Manual deploy from the control node:
--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)
+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_WS_API_BASE_URL=wss://beta.chatbackend.aimloperations.com/ws/chat_again/
+2
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_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" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<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" />
<!--
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.
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>
<body>
+2 -2
View File
@@ -1,6 +1,6 @@
{
"short_name": "Chat by AI ML Operations. LLC",
"name": "Chat by AI ML Operations, LLC",
"short_name": "Hesychia",
"name": "Hesychia",
"icons": [
{
"src": "favicon.ico",
@@ -115,7 +115,7 @@ const DashboardWrapperLayout = ({ children }: DashboardWrapperLayoutProps): JSX.
<Sidenav
color={sidenavColor}
brand={(transparentSidenav && !darkMode) || whiteSidenav ? brandDark : brandWhite}
brandName="Chat by AI ML, Operations, LLC"
brandName="Hesychia"
routes={[]} // {routes}
onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave}
@@ -136,7 +136,7 @@ const DashboardWrapperLayout = ({ children }: DashboardWrapperLayoutProps): JSX.
<Sidenav
color={sidenavColor}
brand={(transparentSidenav && !darkMode) || whiteSidenav ? brandDark : brandWhite}
brandName="AI ML, Operations, LLC"
brandName="Hesychia"
routes={[]} // {routes}
onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave}
@@ -11,10 +11,10 @@ describe('Footer', () => {
it('renders copyright and developer credit', () => {
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(
'href',
'www.aimloperations.com'
'https://www.aimloperations.com'
);
});
});
@@ -5,7 +5,7 @@ const Footer = (): JSX.Element => {
return (
<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>
);
@@ -67,7 +67,7 @@ const Header = ({drawerWidth=0, handleDrawerToggle}: HeaderProps): JSX.Element =
{isLargeScreen ? (
<>
<Typography variant="h6" style={{ flexGrow: 1 }} className='text-white font-weight-bold'>
Chat | AI Ml Operations
Hesychia
</Typography >
<Button color="inherit" onClick={handleDashboardClick}>
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'>
Chat
Hesychia
</Typography >
<IconButton color="inherit" onClick={handleDashboardClick}>
<Dashboard />
@@ -150,7 +150,7 @@ const Header2 = ({ absolute = false, light = false, isMini = false }: Header2Pro
return (
<HeaderContainer>
<Logo onClick={() => navigate('/')}>
<h4>Chat</h4>
<h4>Hesychia</h4>
</Logo>
+2 -2
View File
@@ -57,8 +57,8 @@ const SamplePage: React.FC = () => {
</Container>
<footer className="footer">
<a href="https://aimloperations.com" target="_blank" rel="noopener noreferrer">
Visit AIMLOperations.com
<a href="https://hesychia.ai" target="_blank" rel="noopener noreferrer">
Visit hesychia.ai
</a>
</footer>
</div>
@@ -36,7 +36,7 @@ const TermsOfService = (): JSX.Element => {
</CardContent>
<Divider />
<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 variant="h4">
1. Acceptance of Terms