Modernize frontend and centralize branding
This commit is contained in:
1 parent
bc4542d0fb
commit
2d61d80550
55 files changed
+1901
-14446
No files matched your search
@@ -4,25 +4,26 @@ This skill is the working guide for understanding, changing, and extending the A
|
||||
|
||||
## What this project is
|
||||
|
||||
AnchorHost.eu is a React 18 single-page client for a hosting platform. It combines a public marketing site and documentation with a customer control panel for game servers, VPS instances, databases, websites, account management, support tickets, plugin discovery, and a privileged administration panel. The client talks to an HTTP API and a persistent WebSocket service. Most operations are user initiated, but dashboard data and operational status are kept live through WebSocket events.
|
||||
AnchorHost.eu is a React 19 single-page client for a hosting platform. It combines a public marketing site and documentation with a customer control panel for game servers, VPS instances, databases, websites, account management, support tickets, plugin discovery, and a privileged administration panel. The client talks to an HTTP API and a persistent WebSocket service. Most operations are user initiated, but dashboard data and operational status are kept live through WebSocket events.
|
||||
|
||||
The repository README states that the source was recovered from production source maps. `recovered-production/` keeps a compiled production bundle and maps as a reference artifact; normal development should modify `src/`, not compiled output. This is a frontend-only repository. Backend route implementation, validation, permission enforcement, schemas beyond what the client sends/reads, and server-side side effects cannot be established from this project alone.
|
||||
|
||||
## Runtime and local development
|
||||
|
||||
- React 18.3, Create React App / `react-scripts` 5, React Router 6, Tailwind CSS 3, PostCSS, and Autoprefixer.
|
||||
- `npm start` starts CRA; `npm run build` produces the static bundle; `npm test` is not declared as a project script even though CRA's test runner exists. Do not eject CRA without a clear need.
|
||||
- `src/index.js` mounts the app and imports global CSS. `public/index.html` is the HTML shell.
|
||||
- React 19.3, Vite 8.3, React Router 7, Tailwind CSS 4.3, and the Vite React/Tailwind plugins. Versions are pinned in `package.json`; `package-lock.json` is the reproducible dependency tree.
|
||||
- `npm run dev` (or `npm start`) starts Vite; `npm run build` creates `dist/`; `npm run preview` serves the production build locally. There is no test script currently configured.
|
||||
- `src/index.jsx` mounts the app and imports global CSS. Root `index.html` is the Vite HTML shell; static files under `public/` are served at the site root.
|
||||
- JSX modules use `.jsx` extensions so Vite's parser treats them consistently; plain JavaScript utilities retain `.js`.
|
||||
- `Dockerfile` builds/serves the static app with nginx; `nginx.conf` must preserve SPA route fallback so deep links such as `/dashboard` and `/plugins/:pluginId` resolve to `index.html`.
|
||||
- Runtime environment values are compiled into the frontend. `.env.example` shows `REACT_APP_API_URL=http://localhost:8080` and `REACT_APP_WS_URL=ws://localhost:8081`.
|
||||
- Runtime environment values are compiled into the frontend. `.env.example` shows `VITE_API_URL=http://localhost:8080` and `VITE_WS_URL=ws://localhost:8081`; `VITE_SITE_URL` can override the canonical public URL.
|
||||
- `src/config/api.js` exports `API_BASE_URL`, `WS_BASE_URL`, and `SITE_BASE_URL`. Defaults are `https://anchorhost.eu` and `wss://anchorhost.eu/ws`; URL normalization strips one trailing slash. `SITE_BASE_URL` currently defaults to `API_BASE_URL`. Other code has a few direct origins/relative paths; review those before assuming changing the base URL relocates every request.
|
||||
- Never put secrets in `REACT_APP_*`; these values are public in the generated bundle.
|
||||
- Never put secrets in `VITE_*`; these values are public in the generated bundle.
|
||||
|
||||
## Repository map
|
||||
|
||||
```text
|
||||
src/
|
||||
App.js App shell, routes, auth and global notices/login/register
|
||||
App.jsx App shell, routes, auth and global notices/login/register
|
||||
config/api.js HTTP, WebSocket, and site base URLs
|
||||
index.css Global Tailwind layers, base styles, control/accessibility rules
|
||||
theme/colors.js Canonical named palette
|
||||
@@ -37,11 +38,11 @@ public/assets/ Brand and marketing imagery; asset documentatio
|
||||
recovered-production/ Compiled production snapshot and source maps; reference only
|
||||
```
|
||||
|
||||
The organization is feature-oriented but not fully uniform: large page components (especially `App.js`, `HomePage.js`, and `DashboardPage.js`) contain substantial orchestration and UI, while server/admin/support subfeatures have their own files. Follow existing imports and state ownership before extracting code into a new abstraction.
|
||||
The organization is feature-oriented but not fully uniform: large page components (especially `App.jsx`, `HomePage.jsx`, and `DashboardPage.jsx`) contain substantial orchestration and UI, while server/admin/support subfeatures have their own files. Follow existing imports and state ownership before extracting code into a new abstraction.
|
||||
|
||||
## Routes and application state
|
||||
|
||||
`src/App.js` owns the `BrowserRouter` route table and provides `AuthContext` (authentication flag, user, login/register/logout actions, and loading state). Routes:
|
||||
`src/App.jsx` owns the `BrowserRouter` route table and provides `AuthContext` (authentication flag, user, login/register/logout actions, and loading state). Routes:
|
||||
|
||||
| Path | View | Behavior |
|
||||
| --- | --- | --- |
|
||||
@@ -57,7 +58,7 @@ The organization is feature-oriented but not fully uniform: large page component
|
||||
| `/docs` | redirect | Replaces URL with `/documentation`. |
|
||||
| `*` | redirect | Replaces unknown path with `/`. |
|
||||
|
||||
Authentication is frontend-managed: `anchorhost_user` stores serialized user information and `anchorhost_token` stores a bearer token in `localStorage`. Restored state is parsed by `App.js`; malformed/missing pairs are cleared. This is not a secure cookie session. When changing auth persistence, update all consumers (many feature files read `anchorhost_token` directly), logout behavior, route guards, and WebSocket URL authentication together. OAuth state values are held temporarily in `sessionStorage` under `google_oauth_state` and `apple_oauth_state`. Cookie consent is stored as `cookie_consent=true`.
|
||||
Authentication is frontend-managed: `anchorhost_user` stores serialized user information and `anchorhost_token` stores a bearer token in `localStorage`. Restored state is parsed by `App.jsx`; malformed/missing pairs are cleared. This is not a secure cookie session. When changing auth persistence, update all consumers (many feature files read `anchorhost_token` directly), logout behavior, route guards, and WebSocket URL authentication together. OAuth state values are held temporarily in `sessionStorage` under `google_oauth_state` and `apple_oauth_state`. Cookie consent is stored as `cookie_consent=true`.
|
||||
|
||||
Login, registration, and two-factor challenge/verification primarily travel over the shared WebSocket (see protocol section). Google and Apple login bootstrap through HTTP and then redirect the browser to the returned `auth_url`. Password reset starts through HTTP. Email verification is a separate HTTP action.
|
||||
|
||||
@@ -84,11 +85,11 @@ Maintain the product principles of purpose, agency, familiarity, flexibility, si
|
||||
| `border` / `brightBlack` | `#2F2F2F` | Strong outline and hard-shadow ink. |
|
||||
| `focus` | `#454545` | Focus-adjacent neutral boundary. |
|
||||
| `foreground` | `#D0D0D0` | Body copy. |
|
||||
| `muted` | `#757575` | Secondary labels; do not use for essential small text. |
|
||||
| `muted` | `#898989` | Secondary copy and labels, with enough contrast for small text on the dark surfaces. |
|
||||
| `dim` | `#505050` | Decorative or disabled content only. |
|
||||
| `brightWhite` | `#F5F5F5` | Headings and key values. |
|
||||
| `primary` / `brightBlue` | `#6C99BB` | Primary actions and keyboard focus. |
|
||||
| `blue` | `#547C99` | Secondary accent. |
|
||||
| `accent_secondary` / `blue` | `#6C99BB` | Accent and link color, checked for readable contrast on panel surfaces. |
|
||||
| `yellow` / `brightYellow` | `#D3A04D` | Warning state and selective emphasis. |
|
||||
| semantic green / red / cyan | `#7B9246` / `#A53C23` / `#5EA8A2` | Success, danger, and supporting status roles where required by existing UI. Keep labels/icons with color so meaning never depends on color alone. |
|
||||
|
||||
@@ -103,17 +104,17 @@ Dashboard semantic Tailwind tokens are `dash.surface`, `dash.surfaceElevated`, `
|
||||
- Inputs are forced to at least 16px on narrow viewports to avoid mobile browser zoom. Touch target helpers provide 44px minimums. Horizontal overflow is clipped at the page level; code blocks and tables gain their own horizontal scrolling on mobile.
|
||||
- Global visible focus uses a 2px primary outline. Some dashboard controls opt out with `focus-skip-global` because they draw their own focus ring; preserve a visible keyboard focus indicator when editing those controls.
|
||||
- Number steppers are globally hidden, range sliders use blue thumbs, and scrollbars are thin blue-gray.
|
||||
- `HomePage.js` uses semantic `site-*` classes in `index.css`; this is the public landing-page system. Keep its header, service rows, estimator, FAQ, and footer aligned when adjusting the homepage.
|
||||
- `dashboard-app` and `admin-app` root classes scope cross-panel normalization in `index.css`. Dashboard primitives live in `components/dashboardPrimitives.js`; update them before hand-styling repeated panels.
|
||||
- `HomePage.jsx` uses semantic `site-*` classes in `index.css`; this is the public landing-page system. Keep its header, service rows, estimator, FAQ, and footer aligned when adjusting the homepage.
|
||||
- `dashboard-app` and `admin-app` root classes scope cross-panel normalization in `index.css`. Dashboard primitives live in `components/dashboardPrimitives.jsx`; update them before hand-styling repeated panels.
|
||||
- The homepage hero uses a manually controlled photo gallery backed by the local assets in `public/assets/`; keep arrow and thumbnail controls keyboard accessible and do not add autoplay by default. The homepage service selector and account country selector use the shared `Dropdown` primitive.
|
||||
- `components/dashboardPrimitives.js` exports the shared `Dropdown` and `InlineDropdown`. The dropdown is a portal listbox, supports arrow/Home/End/Enter/Escape and prefix type-ahead, clamps itself to the viewport, and installs outside-click/scroll/resize listeners only while open. Keep popover styling in the global `.ah-dropdown-*` rules because portals render under `document.body`, outside `.app-container`.
|
||||
- `components/dashboardPrimitives.jsx` exports the shared `Dropdown` and `InlineDropdown`. The dropdown is a portal listbox, supports arrow/Home/End/Enter/Escape and prefix type-ahead, clamps itself to the viewport, and installs outside-click/scroll/resize listeners only while open. Keep popover styling in the global `.ah-dropdown-*` rules because portals render under `document.body`, outside `.app-container`.
|
||||
- Visible brand copy uses `AnchorHost.eu`. Preserve lowercase technical identifiers and hostnames such as `anchorhost_token`, `anchorhost.eu`, and downloaded filenames; these are integration contracts, not display copy.
|
||||
- Keep the layout useful at phone/tablet widths; the dashboard is a real management UI and should not depend on hover-only affordances.
|
||||
|
||||
### Interaction and content principles
|
||||
|
||||
- Display loading, empty, error, connected/disconnected, and completion states explicitly. Async work should not leave a button appearing inert.
|
||||
- Use the shared alert/modal patterns in `App.js`, `DashboardPage.js`, and feature components where practical. Confirm operations that delete accounts, servers, backups, or files; some existing flows use `window.confirm` and this pattern is intentional safety feedback.
|
||||
- Use the shared alert/modal patterns in `App.jsx`, `DashboardPage.jsx`, and feature components where practical. Confirm operations that delete accounts, servers, backups, or files; some existing flows use `window.confirm` and this pattern is intentional safety feedback.
|
||||
- Keep server operations scoped by `serverId`, and ticket operations scoped by ticket ID. WebSocket messages are asynchronous; update the UI on the corresponding server acknowledgment/event rather than pretending a request succeeded immediately.
|
||||
- Maintain existing capitalization and plain operational language. Preserve product terms (credits, VPS, SFTP, Modrinth) rather than replacing them with generic labels.
|
||||
- Respect reduced screen space and safe areas; global styles already account for dynamic viewport and mobile safe-area insets in some fixed UI.
|
||||
@@ -134,7 +135,7 @@ All `/api/...` routes below are observed in `src/`. HTTP methods and bodies are
|
||||
| POST | `/api/verify-email` | No | JSON `{ token }`; token is read by `VerifyEmail` from URL query parameters. |
|
||||
| GET | `/api/public/homepage-showcase` | No | Home page expects success and `links` array. |
|
||||
| GET | `/api/public/stats` | No | Home page expects success and `user_count`. |
|
||||
| GET | `/api/pricing` | No | Same route also loaded by `App.js`; keep in sync with public price display. |
|
||||
| GET | `/api/pricing` | No | Same route also loaded by `App.jsx`; keep in sync with public price display. |
|
||||
| GET | `/api/announcements?limit=20` | No | Customer announcements panel; expects `{ success, announcements }`. |
|
||||
| GET | `/api/announcements?limit=50` | No | Admin announcement list loader; public read call. |
|
||||
| GET | `/api/exchange-rates` | No | Currency hook, store, and server creation form; expects `{ success, rates }`. |
|
||||
@@ -150,7 +151,7 @@ All `/api/...` routes below are observed in `src/`. HTTP methods and bodies are
|
||||
| PUT | `/api/user/password` | Bearer | JSON includes `currentPassword` and `newPassword`. |
|
||||
| DELETE | `/api/user/account` | Bearer | JSON `{ confirmation: confirmationText }`; on success the client clears auth storage/logs out. |
|
||||
| GET | `/api/user/export-data` | Bearer | Parses JSON; on `success`, serializes `data.data` as a downloadable JSON file. |
|
||||
| POST | `/api/user/resend-verification` | Bearer | JSON request (inspect `DashboardPage.js` for current body; request is initiated from verification reminder). |
|
||||
| POST | `/api/user/resend-verification` | Bearer | JSON request (inspect `DashboardPage.jsx` for current body; request is initiated from verification reminder). |
|
||||
|
||||
### Servers, provisioning and checkout
|
||||
|
||||
@@ -241,7 +242,7 @@ The following message types are sent by the client. Fields shown are the fields
|
||||
- `read_file { serverId, filePath }`; `write_file { serverId, filePath, content }`; `create_directory { serverId, dirPath }`; `delete_path { serverId, path }`.
|
||||
- `move_path { serverId, srcPath, destPath }`; `copy_path { serverId, paths, ... }`; clipboard paste may send a list of paths.
|
||||
- `download_file { serverId, filePath }`.
|
||||
- Chunk upload: `start_chunked_upload { serverId, filePath, ... }`, then `upload_file_chunk { serverId, filePath, uploadId, chunkIndex, totalChunks, chunkData, ... }`. The UI chunks at 512 KiB and resumes using in-memory upload tracking after reconnect. Keep encoding and acknowledgment flow aligned with `FileManager.js`.
|
||||
- Chunk upload: `start_chunked_upload { serverId, filePath, ... }`, then `upload_file_chunk { serverId, filePath, uploadId, chunkIndex, totalChunks, chunkData, ... }`. The UI chunks at 512 KiB and resumes using in-memory upload tracking after reconnect. Keep encoding and acknowledgment flow aligned with `FileManager.jsx`.
|
||||
- Archive operations: `pack_zip { serverId, dirPath, zipPath }`, `unpack_zip { serverId, zipPath, ... }`.
|
||||
|
||||
**Console and terminal**
|
||||
@@ -258,7 +259,7 @@ The following message types are sent by the client. Fields shown are the fields
|
||||
**Support tickets**
|
||||
|
||||
- `get_tickets { ...filters/pagination... }`, `get_ticket { ticketId }`, `create_ticket { ...form fields... }`, `send_ticket_message { ...ticket and message fields... }`, `update_ticket_status { ...ticket and status fields... }`.
|
||||
- Admin actions include `claim` and `close` (ticket context is sent by the caller); inspect `TicketSystem.js` before changing the exact keys.
|
||||
- Admin actions include `claim` and `close` (ticket context is sent by the caller); inspect `TicketSystem.jsx` before changing the exact keys.
|
||||
|
||||
### Server-to-client event families
|
||||
|
||||
@@ -272,29 +273,29 @@ The UI explicitly handles these message types; the backend's full payloads are n
|
||||
- Console/terminal: `game_console_output`, `game_console_result`, `vps_terminal_output`, `node_terminal_output`.
|
||||
- Backups: `backups_list`, `backup_status_updated`, `backup_deleted`, plus informational restoration status.
|
||||
- Tickets: `tickets_list`, `ticket_created`, `ticket_details`, `ticket_message_sent`, `ticket_status_updated`, `ticket_stats`, `admin_notification_new_ticket`, `ticket_new_message`.
|
||||
- Domain management events are routed through the domain manager callback in `DashboardPage.js` and `DashboardComponents.js`; search both files for `domainMessageTypes` and corresponding handlers when changing that protocol.
|
||||
- Domain management events are routed through the domain manager callback in `DashboardPage.jsx` and `DashboardComponents.jsx`; search both files for `domainMessageTypes` and corresponding handlers when changing that protocol.
|
||||
|
||||
Always inspect the receiving switch/handler as well as the sending call before modifying a WebSocket contract. Preserve correlation fields such as `serverId`, file path, ticket ID, upload ID, or node name so events do not update the wrong active view. Keep high-volume terminal/file events scoped to their relevant UI, and avoid logging secrets or full file contents.
|
||||
|
||||
## Feature ownership and extension map
|
||||
|
||||
- `App.js`: global routes, auth state, login/register UI and WebSocket, OAuth entry points, cookie consent, shared alert/location/pricing configuration. New routes belong in its route table; avoid duplicating auth state in page components.
|
||||
- `HomePage.js`: public brand/product landing page, homepage showcase and public stats. Marketing content and CTA route behavior live here.
|
||||
- `DashboardPage.js`: authenticated customer workspace and its dashboard WebSocket dispatcher. It coordinates server selection, account panels, server actions, 2FA, credits, domain feature hooks, and server detail view composition. Keep dispatcher and child consumers coordinated.
|
||||
- `AdminPage.js` / `AdminSection.js`: admin route shell and admin settings, pricing, announcements, users, servers, cluster nodes, stats, and support actions.
|
||||
- `ServerCreationForm.js`: provisioning configuration, capacity check, exchange rates, and demo eligibility. Creation itself is sent over WebSocket.
|
||||
- `ServerDetailsModal.js`: selected server's metrics/logs/settings/version/ports, SFTP, sync/reinstall HTTP actions, and child tabs.
|
||||
- `FileManager.js`: remote file browsing/editing, safe destructive controls, upload/download, chunk resume, and zip actions. Its callbacks are fed by the dashboard socket; preserve this integration.
|
||||
- `BackupSection.js`, `GameConsole.js`, `VPSTerminal.js`: narrowly scoped server tools driven by WebSocket.
|
||||
- `App.jsx`: global routes, auth state, login/register UI and WebSocket, OAuth entry points, cookie consent, shared alert/location/pricing configuration. New routes belong in its route table; avoid duplicating auth state in page components.
|
||||
- `HomePage.jsx`: public brand/product landing page, homepage showcase and public stats. Marketing content and CTA route behavior live here.
|
||||
- `DashboardPage.jsx`: authenticated customer workspace and its dashboard WebSocket dispatcher. It coordinates server selection, account panels, server actions, 2FA, credits, domain feature hooks, and server detail view composition. Keep dispatcher and child consumers coordinated.
|
||||
- `AdminPage.jsx` / `AdminSection.jsx`: admin route shell and admin settings, pricing, announcements, users, servers, cluster nodes, stats, and support actions.
|
||||
- `ServerCreationForm.jsx`: provisioning configuration, capacity check, exchange rates, and demo eligibility. Creation itself is sent over WebSocket.
|
||||
- `ServerDetailsModal.jsx`: selected server's metrics/logs/settings/version/ports, SFTP, sync/reinstall HTTP actions, and child tabs.
|
||||
- `FileManager.jsx`: remote file browsing/editing, safe destructive controls, upload/download, chunk resume, and zip actions. Its callbacks are fed by the dashboard socket; preserve this integration.
|
||||
- `BackupSection.jsx`, `GameConsole.jsx`, `VPSTerminal.jsx`: narrowly scoped server tools driven by WebSocket.
|
||||
- `StoreSection.js`: credits packages/currency and Stripe session start.
|
||||
- `usePanelCurrency.js`: shared conversion rates/currency state.
|
||||
- `PluginStore.js` and `PluginStoreEmbedded.js`: Modrinth search and two contexts; `PluginDetails.js` loads project versions and installs to a selected server.
|
||||
- `TicketSystem.js`: support-ticket UI and live socket protocol.
|
||||
- `PluginStore.jsx` and `PluginStoreEmbedded.jsx`: Modrinth search and two contexts; `PluginDetails.jsx` loads project versions and installs to a selected server.
|
||||
- `TicketSystem.jsx`: support-ticket UI and live socket protocol.
|
||||
- `AnnouncementsSection.js`: customer announcement list.
|
||||
- `DocumentationPage.js`: long-form in-app documentation. Treat described defaults/credentials as user-facing claims that must match backend behavior.
|
||||
- `LegalDocumentLayout.js`, `TermsOfService.js`, `PrivacyPolicy.js`: shared legal shell and static legal content.
|
||||
- `VerifyEmail.js`: HTTP verification callback view.
|
||||
- `DashboardComponents.js`, `dashboardPrimitives.js`, `components/ui/*`: shared dashboard panels, forms, navigation primitives, buttons/cards; extend before duplicating patterns.
|
||||
- `DocumentationPage.jsx`: long-form in-app documentation. Treat described defaults/credentials as user-facing claims that must match backend behavior.
|
||||
- `LegalDocumentLayout.jsx`, `TermsOfService.jsx`, `PrivacyPolicy.jsx`: shared legal shell and static legal content.
|
||||
- `VerifyEmail.jsx`: HTTP verification callback view.
|
||||
- `DashboardComponents.jsx`, `dashboardPrimitives.jsx`, `components/ui/*`: shared dashboard panels, forms, navigation primitives, buttons/cards; extend before duplicating patterns.
|
||||
|
||||
## Change workflow and quality rules
|
||||
|
||||
|
||||
Reference in new issue
Block a user