The web app is a single-page browser client kept in the webapp/ folder at the repository root. The API server serves it from the same origin under /app, so the browser calls /api/v1 without cross-origin requests. This page describes the folder layout, how files are served and cached, and the rule that screens come from server metadata. Start-up and the API layer are on boot, session, and API calls.
In short¶
- The web app is plain ES modules with no build step:
index.htmlloads one module script,js/main.js(webapp/index.html:406). webapp/js/holds 51 JavaScript files plus thevendor/folder (counted withls webapp/js: 52 entries).- The server mounts the folder twice:
/appwith revalidation on every load, and/app/v/<stamp>/as immutable files (src/cluster_erp/server/app.py:1633-1644at commit 92f8051). - Every list, form, card, action, and module tab is built from
GET /api/v1/_meta(webapp/js/meta.js:16-47). The project's written engineering rules make the web app fully metadata-driven.
How it works¶
Folder layout¶
| Path | Content | Count | How counted |
|---|---|---|---|
webapp/index.html |
The shell: sign-in screen, home screen, app view, overlays, and the module script | 1 file, 408 lines | wc -l |
webapp/operator.html |
The operator console page | 1 file | ls webapp |
webapp/js/ |
Engine and screen modules | 51 .js files and vendor/ |
ls webapp/js |
webapp/js/vendor/pdfjs/ |
Vendored PDF renderer (pdfjs-dist 6.2.108, Apache-2.0) |
4 files | webapp/js/vendor/pdfjs/README.txt |
webapp/css/ |
tokens.css, app.css, gen.css, tiles.css, mail.css |
5 files | ls webapp/css |
webapp/i18n/ |
en.json, tr.json, and the manifest languages.json |
3 files | ls webapp/i18n |
webapp/fonts/ |
Self-hosted Manrope font files, manrope.css, and OFL.txt |
8 files | ls webapp/fonts |
webapp/assets/ |
Chat wallpaper images for the assistant screen | 2 files | ls webapp/assets |
webapp/store/ |
Screenshot galleries for app store entries, one folder per app | 26 folders | ls webapp/store |
The operator console is documented on operator console. The comment in webapp/index.html:8-12 states that the typeface is served from the node so that no visitor request leaves the deployment for a font.
Module groups in the js folder¶
| Group | Files |
|---|---|
| Boot and transport | main.js, api.js, app-session.js, gen-api.js, meta.js, data-bus.js, ui-state.js |
| Generic engines | gen-list.js, gen-form.js, gen-detail.js, gen-tree.js, gen-settings.js, entity.js, action-sheet.js, customselect.js, form-drafts.js, table-align.js, avatar.js |
| Shell | home.js, module-app.js, app-scope.js, nav.js, app-wheel.js, tiles.js, touch-gate.js, device-class.js, search-index.js, custom-widgets.js |
| Widgets | widget-ai.js, widget-approvals.js, widget-scope.js |
| Language and appearance | i18n.js, prefs.js, a11y.js, a11y-ui.js, icons.js, ui.js |
| Screens | general.js, retention.js, changed.js, logs.js, profile.js, mail.js, mail-settings.js, signup.js, record-docs.js, viewer.js, share.js, assistant.js, chat-task.js |
| Operator page | operator.js |
The grouping follows the header comment of each file. It is a reading aid, not a structure in code.
Serving and the asset stamp¶
webapp/index.html links every stylesheet, module, and font under ./v/__ASSET_STAMP__/ (webapp/index.html:13-74). When the server returns index.html, it replaces the placeholder with asset_stamp(webapp_dir), a digest over every file in the folder, and answers with Cache-Control: no-cache and an ETag (src/cluster_erp/server/app.py:1616-1625 at commit 92f8051). A file requested under the current stamp is sent with public, max-age=31536000, immutable. A file under an older stamp is sent with no-cache (src/cluster_erp/server/app.py:1599-1614). A deploy therefore produces a new set of URLs. The stamp function is documented on cache and asset stamp.
The modulepreload list in index.html is generated by web-client/_gen_modulepreload.mjs and is marked as not for hand editing (webapp/index.html:24).
Security headers that shape the client¶
The server sends a content security policy with every response. Scripts may load only from the same origin and from blob: URLs. The comment states that blob: is required for the gated-app module import and for object-URL previews (src/cluster_erp/server/app.py:1325-1352 at commit 92f8051). Framing is limited to the same origin, which the duplicated home tiles need (src/cluster_erp/server/app.py:1348-1351). See gated app bundles and home screen, dock, and launcher.
Why it is built this way¶
- Same-origin serving: the comment in
src/cluster_erp/server/app.py:1574-1576(at commit 92f8051) states that serving the front end from the API server lets the browser reach the API with no CORS. - Two mounts: the comment in
src/cluster_erp/server/app.py:1578-1588states that a reload previously cost 62 revalidation round trips, and that versioned URLs remove them whileindex.htmlstill picks up a deploy at once. - Metadata-driven screens: the project's written engineering rules require that screen, form, list, and action behaviour comes from metadata and forbid UI-specific embedded rules. See metadata-driven UI.
Rules and boundaries¶
- The generic engines
gen-list.js,gen-detail.js,gen-form.js,entity.js, andgen-settings.jsmust not compare against business module names.tests/test_architecture_boundaries.py:75(test_generic_web_engines_do_not_branch_on_business_module_names) enforces this. - Generic web files must not name module paths, module permissions, or per-language columns, and must not branch on a language code.
tests/test_metadata_driven_rules.py:85enforces this for eleven files. - The web app is mounted only when the
webappfolder exists next to the package (src/cluster_erp/server/app.py:1633-1634).
Interaction with other parts¶
- The server side of metadata is documented on metadata model.
- Session cookies and sign-in are documented on authentication and sessions.
- The app catalogue and entitlements behind the home screen are documented on app store, licensing, and entitlements.
- The desktop client renders the same metadata; see the desktop section.
Limits and open points¶
- The folder
web-client/holds the browser test battery and a separate Vite project. Whether that project is in use is not determined from code; see repository map. index.htmldeclareslang="tr"and a Turkish sign-in label in markup (webapp/index.html:2,webapp/index.html:161). Both are replaced at boot by the selected language (webapp/js/i18n.js:81,webapp/js/main.js:221).
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| web app | webapp/ |
The browser client in webapp/ that the server serves at /app. |
web uygulaması | src/cluster_erp/server/app.py:1633 |
| asset stamp placeholder | __ASSET_STAMP__ |
The token in index.html that the server replaces with the current asset stamp. |
varlık damgası yer tutucusu | webapp/index.html:18 |
| versioned mount | /app/v |
The static mount that serves files under a stamp as immutable. | sürümlü bağlama | src/cluster_erp/server/app.py:1635-1639 |
Related pages¶
- Web app platform
- Boot, session, and API calls
- Metadata rendering
- Cache and asset stamp
- Request pipeline and middleware
Verified against commit 92f8051 on 2026-11-13.