docs(generic): clarify frontend directory naming is not fixed to "web/"
The "web/" folder name in §4 was being read as a required convention, but projects routinely use ui/, dashboard/, or admin/ instead — and may have more than one frontend in the same repo. Document the common names, note that each frontend is an independent Vite app, and add guidance on sharing types across multiple frontends. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
18
generic.md
18
generic.md
@@ -22,7 +22,7 @@ Projects are Rust cargo workspaces. The repository root contains:
|
|||||||
│ ├── <app>-api/ # binary: REST / JSON / WebSocket daemon
|
│ ├── <app>-api/ # binary: REST / JSON / WebSocket daemon
|
||||||
│ ├── <app>-worker/ # binary: long-running processor / queue consumer
|
│ ├── <app>-worker/ # binary: long-running processor / queue consumer
|
||||||
│ └── <app>-cli/ # binary: operator / admin CLI
|
│ └── <app>-cli/ # binary: operator / admin CLI
|
||||||
├── web/ # Vite + React + SWC + TS frontend (when applicable)
|
├── <frontend-dir>/ # Vite + React + SWC + TS frontend(s) — see §4
|
||||||
├── asset/ # deployment artifacts (see §6)
|
├── asset/ # deployment artifacts (see §6)
|
||||||
├── script/ # deploy.sh and related operational scripts
|
├── script/ # deploy.sh and related operational scripts
|
||||||
└── README.md
|
└── README.md
|
||||||
@@ -130,10 +130,19 @@ API and worker binaries are managed by systemd unit files shipped from `asset/sy
|
|||||||
## 4. Frontends
|
## 4. Frontends
|
||||||
|
|
||||||
### Web (default)
|
### Web (default)
|
||||||
Vite + React + SWC + TypeScript, in `<repo-root>/web/`:
|
Vite + React + SWC + TypeScript. The frontend lives in a top-level directory named for what it *is* to the user, not a generic `web/`. Common names:
|
||||||
|
|
||||||
|
- `web/` — the primary public-facing app, when there's only one frontend
|
||||||
|
- `ui/` — equivalent, when the project prefers this naming
|
||||||
|
- `dashboard/` — a user-facing dashboard UI
|
||||||
|
- `admin/` — an operator/admin console distinct from the public UI
|
||||||
|
|
||||||
|
A project may have more than one of these (e.g., both `dashboard/` and `admin/`). Each is an independent Vite app with its own `package.json`, built and deployed separately, typically served from its own nginx `server_name` or path prefix. Pick names that describe the audience or purpose; don't invent a generic wrapper directory to hold them.
|
||||||
|
|
||||||
|
Whatever the directory is called, the internal structure is the same:
|
||||||
|
|
||||||
```
|
```
|
||||||
web/
|
<frontend-dir>/
|
||||||
├── package.json
|
├── package.json
|
||||||
├── vite.config.ts
|
├── vite.config.ts
|
||||||
├── tsconfig.json
|
├── tsconfig.json
|
||||||
@@ -150,6 +159,7 @@ web/
|
|||||||
- Build output is static. Deployed to an nginx CDN endpoint — no Node.js in production.
|
- Build output is static. Deployed to an nginx CDN endpoint — no Node.js in production.
|
||||||
- API base URL is configured at build time (Vite `import.meta.env.VITE_API_BASE_URL`) and stamped per environment during deploy.
|
- API base URL is configured at build time (Vite `import.meta.env.VITE_API_BASE_URL`) and stamped per environment during deploy.
|
||||||
- Prefer React Query or equivalent for server state. Keep business logic server-side; the frontend is a rendering and interaction layer.
|
- Prefer React Query or equivalent for server state. Keep business logic server-side; the frontend is a rendering and interaction layer.
|
||||||
|
- When a project has multiple frontends, they may share types via a local package (e.g., `packages/shared-types/`) or via generated TypeScript bindings from the Rust `entities` crate. Don't duplicate API clients across frontends — factor the shared bits out.
|
||||||
|
|
||||||
### Web (Rust framework exception)
|
### Web (Rust framework exception)
|
||||||
Use a Rust web framework (Axum + templating, or a fullstack framework) **only when** the deployment model requires a single self-contained binary with no external web server — e.g., distributed orchestration nodes that each serve their own UI over TLS. The Cichlid pattern. Default is still Vite + nginx.
|
Use a Rust web framework (Axum + templating, or a fullstack framework) **only when** the deployment model requires a single self-contained binary with no external web server — e.g., distributed orchestration nodes that each serve their own UI over TLS. The Cichlid pattern. Default is still Vite + nginx.
|
||||||
@@ -516,7 +526,7 @@ When scaffolding or extending a project:
|
|||||||
5. Any new deployable component gets an entry in `asset/manifest.yml`, a systemd unit in `asset/systemd/`, a sysusers drop-in, a firewalld service XML, and any required SELinux assets — in the same change.
|
5. Any new deployable component gets an entry in `asset/manifest.yml`, a systemd unit in `asset/systemd/`, a sysusers drop-in, a firewalld service XML, and any required SELinux assets — in the same change.
|
||||||
6. Config templates go in `asset/config/` with `{{PLACEHOLDER}}` secrets. Never commit a rendered config.
|
6. Config templates go in `asset/config/` with `{{PLACEHOLDER}}` secrets. Never commit a rendered config.
|
||||||
7. Postgres connections are mTLS, passwordless. If writing connection code that accepts a password, stop and ask.
|
7. Postgres connections are mTLS, passwordless. If writing connection code that accepts a password, stop and ask.
|
||||||
8. Frontend is Vite + React + SWC + TS, served as static assets from nginx. Rust web frameworks require a stated reason.
|
8. Frontends are Vite + React + SWC + TS, served as static assets from nginx. Name the directory after its audience (`web/`, `ui/`, `dashboard/`, `admin/`) — `web/` is not a mandated convention. Rust web frameworks require a stated reason.
|
||||||
9. Services run as dedicated non-root users with hardened systemd units per §8. Root requires explicit justification.
|
9. Services run as dedicated non-root users with hardened systemd units per §8. Root requires explicit justification.
|
||||||
10. Every listening port gets a named firewalld service per §9. No bare `--add-port` calls.
|
10. Every listening port gets a named firewalld service per §9. No bare `--add-port` calls.
|
||||||
11. SELinux stays enforcing. Work with the default policy first; ship a custom module only when necessary (§10). Never suggest `setenforce 0`.
|
11. SELinux stays enforcing. Work with the default policy first; ship a custom module only when necessary (§10). Never suggest `setenforce 0`.
|
||||||
|
|||||||
Reference in New Issue
Block a user