Author SHA1 Message Date
westfarn 9e1449f0db Add public account-deletion page for Google Play (#103) (#110)
Deploy Beta / unit-tests (push) Successful in 12s
Unit Tests / test (push) Successful in 11s
Deploy Beta / deploy-beta (push) Successful in 2m23s
## Summary
- Closes [#103](#103).
- Adds public SPA route `/account-deletion/` (no auth) with Hesychia / `ai.hesychia.chat` branding, in-app deletion steps, soft-delete data retention copy, and a contact path (30-day SLA) for users who cannot sign in.
- Documents Play Console **Account deletion URL** in `ANDROID.md` and `android/README.md` (`https://hesychia.ai/account-deletion/`, legacy host, HashRouter form).

## Notes
- Retention copy matches backend soft-delete (v1): no claim of full erasure / hard purge yet.
- Play Console field still needs to be set out-of-band after deploy.

## Test plan
- [ ] Open `/account-deletion/` signed out — page loads (no redirect to sign-in)
- [ ] Confirm steps match Account → Delete my account + email confirm
- [ ] Confirm retention sections are accurate vs soft-delete
- [ ] `npm run test:ci -- --testPathPattern=AccountDeletionPage`
- [ ] After beta deploy, set Play Console Account deletion URL to the public HTTPS URLReviewed-on: #110
2026-08-04 10:53:48 -07:00
westfarn 0aad5394e9 Default to THINKING; hide Sources card (#108) (#109)
Deploy Beta / deploy-beta (push) Successful in 2m22s
Deploy Beta / unit-tests (push) Successful in 11s
Unit Tests / test (push) Successful in 12s
## Summary
- Closes [#108](#108) — hide Sources card; clicking inline `[n]` opens that source in a new tab.
- Follow-up to [#106](#106) / [#107](#107): default fixed `modelName` is now `THINKING` (not `FAST`).

## Test plan
- [ ] Sent messages use THINKING.
- [ ] Grounded answers show inline `[n]` markers but no Sources card.
- [ ] Clicking `[n]` opens the matching URL in a new tab.Reviewed-on: #109
2026-08-04 10:41:15 -07:00
westfarn 6ec239d2e0 Remove FAST/THINKING model dropdown from chat composer (#106) (#107)
Deploy Beta / unit-tests (push) Successful in 12s
Unit Tests / test (push) Successful in 11s
Deploy Beta / deploy-beta (push) Successful in 2m20s
## Summary
- Closes [#106](#106).
- Removes the FAST / THINKING `<select>` from the chat input bar.
- Continues to send a fixed `modelName` of `FAST` on WebSocket sends so the backend contract is unchanged.

## Test plan
- [ ] Open chat dashboard — composer shows attach + text field + send only (no FAST/THINKING dropdown).
- [ ] Send a message — stream still works.
- [ ] Send with attachment — still works.Reviewed-on: #107
2026-08-04 10:17:32 -07:00
5 changed files with 188 additions and 6 deletions
+11 -3
View File
@@ -132,12 +132,20 @@ Out of band ops (not automated here):
1. Google Play developer account
2. Privacy policy URL (product site / legal)
3. Data safety form (JWT auth, chat content, analytics if Tianji runs in WebView)
4. Screenshots for phone (+ tablet if targeting)
5. Upload `.aab` to **internal testing** track before production
3. **Account deletion URL** (Data safety / Account deletion) → public page:
- Canonical: `https://hesychia.ai/account-deletion/`
- Legacy host until DNS cutover: `https://chat.aimloperations.com/account-deletion/`
- Capacitor HashRouter: `/#/account-deletion/`
4. Data safety form (JWT auth, chat content, analytics if Tianji runs in WebView)
5. Screenshots for phone (+ tablet if targeting)
6. Upload `.aab` to **internal testing** track before production
In-app delete remains Account → **Delete my account** (`DELETE /api/user/`). The public URL
above is for Play reviewers and users who never open the app (#103).
## Related issues
- [#20](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/20) — this Android wrap
- [#21](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/21) — iOS (reuses this scaffolding)
- [#22](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/22) / [#23](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/23) / [#24](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/24) — auth / WS / routing
- [#103](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/103) — Play public account-deletion URL
+9 -3
View File
@@ -107,9 +107,15 @@ Without `keystore.properties`, release builds are unsigned; debug builds do not
1. [Play Console](https://play.google.com/console) → app **Hesychia** (`ai.hesychia.chat`).
2. Complete store listing: privacy policy URL, data-safety form, screenshots.
3. **Testing → Internal testing** → create release → upload `app-release.aab`.
4. Add testers, roll out internal track, verify on devices.
5. Promote to closed / open / production only after internal QA passes.
3. Set **Account deletion URL** to the public instructions page (no sign-in required):
- `https://hesychia.ai/account-deletion/` (preferred product host)
- or `https://chat.aimloperations.com/account-deletion/` until hesychia.ai cutover
4. **Testing → Internal testing** → create release → upload `app-release.aab`.
5. Add testers, roll out internal track, verify on devices.
6. Promote to closed / open / production only after internal QA passes.
See also [`../ANDROID.md`](../ANDROID.md) Play checklist and issue
[#103](https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/103).
Each new upload needs a higher `versionCode`.
+3
View File
@@ -11,6 +11,7 @@ import NotFound from './llm-fe/pages/NotFound/NotFound';
import { AuthContext } from './llm-fe/contexts/AuthContext';
import TermsOfService from './llm-fe/pages/TermsOfService/TermsOfService';
import PublicTermsOfServicePage from './llm-fe/pages/TermsOfService/PublicTermsOfServicePage';
import AccountDeletionPage from './llm-fe/pages/AccountDeletion/AccountDeletionPage';
import SetPassword from './llm-fe/components/SetPassword/SetPassword';
import AsyncDashboard2 from './llm-fe/pages/AsyncDashboard2/AsyncDashboard2';
import FeedbackPage2 from './llm-fe/pages/FeedbackPage2/FeedbackPage2';
@@ -71,6 +72,8 @@ class App extends Component {
{/* Public legal pages (also used for post-login ToS acknowledge) */}
<Route path={"/terms_of_service/"} Component={TermsOfService} />
<Route path={"/legal/terms-of-service"} Component={PublicTermsOfServicePage} />
{/* Play Console account-deletion URL (#103) — must stay public */}
<Route path={"/account-deletion/"} Component={AccountDeletionPage} />
<Route element={<ProtectedRoutes />}>
<Route path={"/"} index={true} Component={AsyncDashboard2} />
@@ -0,0 +1,35 @@
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import AccountDeletionPage from './AccountDeletionPage';
describe('AccountDeletionPage', () => {
it('renders Hesychia deletion steps and retention copy without auth', () => {
render(
<MemoryRouter>
<AccountDeletionPage />
</MemoryRouter>,
);
expect(
screen.getByRole('heading', { name: /Hesychia — Request account deletion/i }),
).toBeInTheDocument();
expect(screen.getByText(/ai\.hesychia\.chat/i)).toBeInTheDocument();
expect(
screen.getByRole('heading', { name: /How to delete your account/i }),
).toBeInTheDocument();
expect(screen.getByText(/Delete my account/i)).toBeInTheDocument();
expect(
screen.getByRole('heading', { name: /Deactivated immediately/i }),
).toBeInTheDocument();
expect(
screen.getByRole('heading', { name: /Data retained after soft-delete/i }),
).toBeInTheDocument();
expect(screen.getByRole('heading', { name: /Retention period/i })).toBeInTheDocument();
expect(screen.getByText(/no automatic hard-purge schedule/i)).toBeInTheDocument();
expect(
screen.getByRole('heading', { name: /Cannot access your account/i }),
).toBeInTheDocument();
expect(screen.getByText(/30 days/i)).toBeInTheDocument();
});
});
@@ -0,0 +1,130 @@
import React from 'react';
import { Box, Button, Card, CardContent, Divider, Stack, Typography } from '@mui/material';
import { Link as RouterLink } from 'react-router-dom';
/**
* Public Play / App Store account-deletion instructions (#103).
* No auth required — reviewers and signed-out users must be able to read this page.
*/
const AccountDeletionPage = (): JSX.Element => (
<Box sx={{ py: 4, px: 2, minHeight: '100vh', bgcolor: 'background.default' }}>
<Card sx={{ maxWidth: 900, mx: 'auto', width: '100%' }}>
<CardContent>
<Typography variant="h3" component="h1" gutterBottom>
Hesychia Request account deletion
</Typography>
<Typography variant="subtitle1" color="text.secondary" gutterBottom>
Hesychia (ai.hesychia.chat) · hesychia.ai · AI ML Operations, LLC
</Typography>
<Typography variant="body1" color="text.secondary">
Use the steps below to request deletion of your Hesychia account. This page does not
require sign-in to read.
</Typography>
</CardContent>
<Divider />
<CardContent>
<Stack spacing={3}>
<Box>
<Typography variant="h5" component="h2" gutterBottom>
How to delete your account
</Typography>
<Typography variant="body1" component="ol" sx={{ pl: 2.5, m: 0 }}>
<li>
Open <strong>Hesychia</strong> in the mobile app or at{' '}
<a href="https://hesychia.ai" rel="noopener noreferrer">
hesychia.ai
</a>
.
</li>
<li>Sign in with the account you want deleted.</li>
<li>
Go to <strong>Account</strong>.
</li>
<li>
Choose <strong>Delete my account</strong>, then confirm by typing your account
email.
</li>
</Typography>
</Box>
<Box>
<Typography variant="h5" component="h2" gutterBottom>
What happens when you delete
</Typography>
<Typography variant="h6" component="h3" gutterBottom sx={{ mt: 2 }}>
Deactivated immediately
</Typography>
<Typography variant="body1" component="ul" sx={{ pl: 2.5, m: 0 }}>
<li>Your account is marked deleted and set inactive.</li>
<li>You lose access to Hesychia and cannot sign in again with that account.</li>
<li>Your conversations are hidden from the product.</li>
<li>Active sessions are invalidated (refresh tokens are blacklisted).</li>
</Typography>
<Typography variant="h6" component="h3" gutterBottom sx={{ mt: 2 }}>
Data retained after soft-delete
</Typography>
<Typography variant="body1" paragraph>
Hesychia currently uses a <strong>soft-delete</strong> process. After you delete your
account, personal data associated with the account (including profile details,
conversation content, uploaded documents / RAG vectors, and authentication event
records) may remain in our systems for administration, security, and audit purposes.
This is not a full erasure of all stored data.
</Typography>
<Typography variant="h6" component="h3" gutterBottom>
Retention period
</Typography>
<Typography variant="body1" paragraph sx={{ mb: 0 }}>
There is currently <strong>no automatic hard-purge schedule</strong>. Soft-deleted
data is retained until a future purge process is implemented or until we process a
separate retention / erasure request through the contact path below. We will not claim
complete erasure while soft-delete-only remains in effect.
</Typography>
</Box>
<Box>
<Typography variant="h5" component="h2" gutterBottom>
Cannot access your account?
</Typography>
<Typography variant="body1" paragraph>
If you cannot sign in to complete in-app deletion, contact AI ML Operations, LLC via{' '}
<a href="https://www.aimloperations.com" rel="noopener noreferrer">
aimloperations.com
</a>{' '}
and include the email address used for your Hesychia account. We aim to respond to
account-deletion requests within <strong>30 days</strong>.
</Typography>
<Typography variant="body2" color="text.secondary">
Staff accounts cannot self-delete in the app; use the contact path above.
</Typography>
</Box>
</Stack>
</CardContent>
<Divider />
<CardContent>
<Typography variant="body2" color="text.secondary">
Already have an account?{' '}
<Button component={RouterLink} to="/signin/" size="small">
Sign in
</Button>{' '}
·{' '}
<Button component={RouterLink} to="/account/" size="small">
Account
</Button>{' '}
·{' '}
<Button component={RouterLink} to="/terms_of_service/" size="small">
Terms of Service
</Button>
</Typography>
</CardContent>
</Card>
</Box>
);
export default AccountDeletionPage;