jsgui3-server 0.0.149 → 0.0.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/.github/agents/Mobile Developer.agent.md +89 -0
  2. package/AGENTS.md +4 -0
  3. package/README.md +130 -0
  4. package/admin-ui/client.js +73 -43
  5. package/admin-ui/v1/admin_auth_service.js +197 -0
  6. package/admin-ui/v1/admin_user_store.js +71 -0
  7. package/admin-ui/v1/client.js +17 -0
  8. package/admin-ui/v1/controls/admin_shell.js +1399 -0
  9. package/admin-ui/v1/controls/group_box.js +84 -0
  10. package/admin-ui/v1/controls/stat_card.js +125 -0
  11. package/admin-ui/v1/server.js +658 -0
  12. package/admin-ui/v1/utils/formatters.js +68 -0
  13. package/docs/admin-extension-guide.md +345 -0
  14. package/docs/books/adaptive-control-improvements/01-control-candidate-matrix.md +122 -0
  15. package/docs/books/adaptive-control-improvements/02-tier-1-layout-playbooks.md +207 -0
  16. package/docs/books/adaptive-control-improvements/03-tier-2-navigation-form-overlay.md +140 -0
  17. package/docs/books/adaptive-control-improvements/04-cross-cutting-platform-functionality.md +141 -0
  18. package/docs/books/adaptive-control-improvements/05-styling-theming-density-upgrades.md +114 -0
  19. package/docs/books/adaptive-control-improvements/06-testing-quality-gates.md +97 -0
  20. package/docs/books/adaptive-control-improvements/07-delivery-roadmap-and-ownership.md +137 -0
  21. package/docs/books/adaptive-control-improvements/08-appendix-tier1-acceptance-and-pr-templates.md +261 -0
  22. package/docs/books/adaptive-control-improvements/README.md +66 -0
  23. package/docs/books/admin-ui-authentication/01-threat-model-and-goals.md +124 -0
  24. package/docs/books/admin-ui-authentication/02-session-model-and-token-model.md +75 -0
  25. package/docs/books/admin-ui-authentication/03-auth-middleware-patterns.md +77 -0
  26. package/docs/books/admin-ui-authentication/README.md +25 -0
  27. package/docs/books/creating-a-new-admin-ui/01-introduction-and-vision.md +130 -0
  28. package/docs/books/creating-a-new-admin-ui/02-architecture-and-data-flow.md +298 -0
  29. package/docs/books/creating-a-new-admin-ui/03-server-introspection.md +381 -0
  30. package/docs/books/creating-a-new-admin-ui/04-admin-module-adapter-layer.md +592 -0
  31. package/docs/books/creating-a-new-admin-ui/05-domain-controls-stat-cards-and-gauges.md +513 -0
  32. package/docs/books/creating-a-new-admin-ui/06-domain-controls-process-manager.md +544 -0
  33. package/docs/books/creating-a-new-admin-ui/07-domain-controls-resource-pool-inspector.md +493 -0
  34. package/docs/books/creating-a-new-admin-ui/08-domain-controls-route-table-and-api-explorer.md +586 -0
  35. package/docs/books/creating-a-new-admin-ui/09-domain-controls-log-viewer-and-activity-feed.md +490 -0
  36. package/docs/books/creating-a-new-admin-ui/10-domain-controls-build-status-and-bundle-inspector.md +526 -0
  37. package/docs/books/creating-a-new-admin-ui/11-domain-controls-configuration-panel.md +808 -0
  38. package/docs/books/creating-a-new-admin-ui/12-admin-shell-layout-sidebar-navigation.md +210 -0
  39. package/docs/books/creating-a-new-admin-ui/13-telemetry-integration.md +556 -0
  40. package/docs/books/creating-a-new-admin-ui/14-realtime-sse-observable-integration.md +485 -0
  41. package/docs/books/creating-a-new-admin-ui/15-styling-theming-aero-design-system.md +521 -0
  42. package/docs/books/creating-a-new-admin-ui/16-testing-and-quality-assurance.md +147 -0
  43. package/docs/books/creating-a-new-admin-ui/17-next-steps-process-resource-roadmap.md +356 -0
  44. package/docs/books/creating-a-new-admin-ui/README.md +68 -0
  45. package/docs/books/device-adaptive-composition/01-platform-feature-audit.md +177 -0
  46. package/docs/books/device-adaptive-composition/02-responsive-composition-model.md +187 -0
  47. package/docs/books/device-adaptive-composition/03-data-model-vs-view-model.md +231 -0
  48. package/docs/books/device-adaptive-composition/04-styling-theme-breakpoints.md +234 -0
  49. package/docs/books/device-adaptive-composition/05-showcase-app-multi-device-assessment.md +193 -0
  50. package/docs/books/device-adaptive-composition/06-implementation-patterns-and-apis.md +346 -0
  51. package/docs/books/device-adaptive-composition/07-testing-harness-and-quality-gates.md +265 -0
  52. package/docs/books/device-adaptive-composition/08-roadmap-and-adoption-plan.md +250 -0
  53. package/docs/books/device-adaptive-composition/README.md +47 -0
  54. package/docs/comparison-report-express-plex-cpanel.md +549 -0
  55. package/docs/designs/server-admin-interface-aero.svg +611 -0
  56. package/docs/troubleshooting.md +84 -53
  57. package/module.js +16 -11
  58. package/package.json +1 -1
  59. package/serve-factory.js +1 -0
  60. package/server.js +199 -0
  61. package/tests/README.md +5 -0
  62. package/tests/admin-ui-jsgui-controls.test.js +581 -0
  63. package/tests/test-runner.js +1 -0
  64. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-071799b982906680f5fd699d.js +0 -40
  65. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-07352945ad5c92654fcb8b65.js +0 -39
  66. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-138a601fadb6191ea314c6fd.js +0 -39
  67. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-171f6c381c2cadf2e9fa7087.js +0 -39
  68. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-1d973388156b84a04373fac9.js +0 -39
  69. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-20e117bc8a10d2cd16234bbe.js +0 -40
  70. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-2b028a82b0e5efddba42425f.js +0 -39
  71. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-4518556cd5c7e059e82b22b8.js +0 -40
  72. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5bac1aa0f213902f718ed74f.js +0 -40
  73. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5f9996ac7822caf777d92f56.js +0 -39
  74. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-60a92c702e65fd9cf748e3ec.js +0 -39
  75. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6164c1f8f738995c541895d2.js +0 -44
  76. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6718a85eb9e5aa782dd47a05.js +0 -45
  77. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-69e280f14e37aee76a1d4675.js +0 -39
  78. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7570d1b030d44b111ed59c4c.js +0 -39
  79. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7798c9bbd55e510d5039f936.js +0 -42
  80. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-78cd511ea1ef18ecb03d1be5.js +0 -40
  81. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7d482e0b95bcb5e3c543118b.js +0 -43
  82. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-80e9476d1127c55b40fdb36f.js +0 -40
  83. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-810ced55d5320a3088a05b13.js +0 -40
  84. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-8423565f1a40e329afc8c6cf.js +0 -40
  85. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-900bef783b8cee36506ec282.js +0 -39
  86. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-a1a37aff6416fdad74040ddf.js +0 -39
  87. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-ad48d5e8eda40f175b4df090.js +0 -39
  88. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-aec5a2d963015528c9099462.js +0 -39
  89. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-af9d34e0f1722fab9e28c269.js +0 -39
  90. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-b818e4015e2f1fe86280b5ab.js +0 -41
  91. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bcb2541adc70b7aba61768c5.js +0 -44
  92. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bfe89d2c78ed44f95ed7dd73.js +0 -40
  93. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c06f04806a1e688e1187110c.js +0 -40
  94. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c3f3adf904f585afc544b96a.js +0 -39
  95. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-d45acb873e1d8e32d5e60f2e.js +0 -39
  96. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-db06f132533706f4a0163b8c.js +0 -39
  97. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f660f40d78b135fc8560a862.js +0 -39
  98. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f9dee4ec18a96e09bee06bae.js +0 -39
@@ -0,0 +1,68 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Format a byte count into a human-readable string.
5
+ * @param {number} bytes
6
+ * @returns {string}
7
+ */
8
+ function format_bytes(bytes) {
9
+ if (bytes === 0 || bytes === null || bytes === undefined) return '0 B';
10
+ const units = ['B', 'KB', 'MB', 'GB'];
11
+ const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(1024));
12
+ const index = Math.min(i, units.length - 1);
13
+ const value = bytes / Math.pow(1024, index);
14
+ return (index > 0 ? value.toFixed(1) : Math.round(value)) + ' ' + units[index];
15
+ }
16
+
17
+ /**
18
+ * Format seconds into a human-readable uptime string.
19
+ * @param {number} seconds
20
+ * @returns {string}
21
+ */
22
+ function format_uptime(seconds) {
23
+ if (seconds === null || seconds === undefined || seconds < 0) return '—';
24
+ seconds = Math.floor(seconds);
25
+ if (seconds < 60) return seconds + 's';
26
+
27
+ const days = Math.floor(seconds / 86400);
28
+ const hours = Math.floor((seconds % 86400) / 3600);
29
+ const minutes = Math.floor((seconds % 3600) / 60);
30
+ const secs = seconds % 60;
31
+
32
+ if (days > 0) return days + 'd ' + hours + 'h';
33
+ if (hours > 0) return hours + 'h ' + minutes + 'm';
34
+ return minutes + 'm ' + secs + 's';
35
+ }
36
+
37
+ /**
38
+ * Format a timestamp into HH:MM:SS.
39
+ * @param {number} timestamp - Unix milliseconds
40
+ * @returns {string}
41
+ */
42
+ function format_time(timestamp) {
43
+ if (!timestamp) return '--:--:--';
44
+ const d = new Date(timestamp);
45
+ const pad = (n) => String(n).padStart(2, '0');
46
+ return pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds());
47
+ }
48
+
49
+ /**
50
+ * Format a timestamp into a relative human-readable string.
51
+ * @param {number} timestamp - Unix milliseconds
52
+ * @returns {string}
53
+ */
54
+ function format_relative_time(timestamp) {
55
+ if (!timestamp) return '—';
56
+ const diff = Date.now() - timestamp;
57
+ if (diff < 60000) return 'just now';
58
+ if (diff < 3600000) return Math.floor(diff / 60000) + ' minutes ago';
59
+ if (diff < 86400000) return Math.floor(diff / 3600000) + ' hours ago';
60
+ return new Date(timestamp).toLocaleString();
61
+ }
62
+
63
+ module.exports = {
64
+ format_bytes,
65
+ format_uptime,
66
+ format_time,
67
+ format_relative_time
68
+ };
@@ -0,0 +1,345 @@
1
+ # Admin UI Extension Guide
2
+
3
+ ## Overview
4
+
5
+ The jsgui3-server admin dashboard (`/admin/v1`) is fully extensible. You can:
6
+
7
+ 1. **Disable** the admin UI entirely
8
+ 2. **Add custom sidebar sections** with automatic data rendering
9
+ 3. **Add custom protected API endpoints** with role-based auth
10
+ 4. **Use plugins** to bundle related admin extensions
11
+ 5. **Access admin internals** (auth service, user store, SSE channel) for advanced use
12
+
13
+ All extension APIs follow snake_case naming and return `this` for chaining.
14
+
15
+ ---
16
+
17
+ ## Quick Start
18
+
19
+ ```javascript
20
+ const Server = require('jsgui3-server');
21
+
22
+ const server = await Server.serve(MyControl, { port: 8080 });
23
+
24
+ // Add a custom section — shows up in the sidebar
25
+ server.admin_v1.add_section({
26
+ id: 'my_data',
27
+ label: 'My Data',
28
+ api_path: '/api/admin/v1/my-data',
29
+ handler: (req, res) => {
30
+ res.writeHead(200, { 'Content-Type': 'application/json' });
31
+ res.end(JSON.stringify([
32
+ { name: 'Item A', value: 42 },
33
+ { name: 'Item B', value: 99 }
34
+ ]));
35
+ }
36
+ });
37
+ ```
38
+
39
+ That's it. The sidebar section appears automatically, and clicking it shows a table.
40
+
41
+ ---
42
+
43
+ ## API Reference
44
+
45
+ ### `admin_v1.add_section(options)`
46
+
47
+ Register a custom sidebar section.
48
+
49
+ | Parameter | Type | Required | Default | Description |
50
+ |----------------|-----------|----------|----------------|-------------|
51
+ | `id` | `string` | Yes | — | Unique section identifier (snake_case) |
52
+ | `label` | `string` | Yes | — | Human-readable sidebar label |
53
+ | `icon` | `string` | No | `null` | Emoji or text icon prefix |
54
+ | `api_path` | `string` | Yes | — | Data endpoint path |
55
+ | `role` | `string` | No | `'admin_read'` | Required role to view |
56
+ | `handler` | `Function`| No | — | `(req, res)` handler for the endpoint |
57
+
58
+ **Returns:** `Admin_Module_V1` (chainable)
59
+
60
+ If `handler` is provided, it is automatically registered as a protected endpoint at `api_path`. If omitted, you must register the endpoint separately with `add_endpoint()` or via `server.publish()`.
61
+
62
+ #### Auto-Rendering Behaviour
63
+
64
+ The admin shell fetches `api_path` and renders the response based on its shape:
65
+
66
+ | Response Shape | Rendered As |
67
+ |------------------------|-----------------------|
68
+ | Array of objects | Table (columns = keys)|
69
+ | Object | Key-value panel |
70
+ | Scalar (string/number) | Plain text block |
71
+ | Empty array | "No data" message |
72
+
73
+ The v1 shell builds these panels with jsgui controls (table rows, key-value rows, buttons) rather than string-based `innerHTML` rendering.
74
+
75
+ #### Example: Array → Table
76
+
77
+ ```javascript
78
+ // Handler returns:
79
+ [
80
+ { name: 'Worker 1', status: 'running', cpu: '12%' },
81
+ { name: 'Worker 2', status: 'idle', cpu: '0%' }
82
+ ]
83
+ // Renders as a 3-column table: Name | Status | CPU
84
+ ```
85
+
86
+ #### Example: Object → Key-Value
87
+
88
+ ```javascript
89
+ // Handler returns:
90
+ { version: '2.1.0', uptime: '4h 12m', mode: 'production' }
91
+ // Renders as Key-Value pairs
92
+ ```
93
+
94
+ ---
95
+
96
+ ### `admin_v1.add_endpoint(options)`
97
+
98
+ Register a custom protected API endpoint.
99
+
100
+ | Parameter | Type | Required | Default | Description |
101
+ |-----------|-----------|----------|----------------|-------------|
102
+ | `path` | `string` | Yes | — | Route path |
103
+ | `role` | `string` | No | `'admin_read'` | Required role |
104
+ | `handler` | `Function`| Yes | — | `(req, res)` handler |
105
+
106
+ **Returns:** `Admin_Module_V1` (chainable)
107
+
108
+ The endpoint is automatically wrapped with role-based authentication. Unauthenticated requests get 401, insufficient-role requests get 403.
109
+
110
+ ```javascript
111
+ server.admin_v1.add_endpoint({
112
+ path: '/api/admin/v1/workers/restart',
113
+ role: 'admin_write',
114
+ handler: (req, res) => {
115
+ // restart logic ...
116
+ res.writeHead(200, { 'Content-Type': 'application/json' });
117
+ res.end(JSON.stringify({ ok: true }));
118
+ }
119
+ });
120
+ ```
121
+
122
+ ---
123
+
124
+ ### `admin_v1.use(plugin_fn)`
125
+
126
+ Plugin-style extension point. The function receives the admin module instance.
127
+
128
+ **Returns:** `Admin_Module_V1` (chainable)
129
+
130
+ ```javascript
131
+ // my_admin_plugin.js
132
+ function my_admin_plugin(admin) {
133
+ admin.add_section({
134
+ id: 'metrics',
135
+ label: 'Metrics',
136
+ icon: '📊',
137
+ api_path: '/api/admin/v1/metrics',
138
+ handler: (req, res) => {
139
+ res.writeHead(200, { 'Content-Type': 'application/json' });
140
+ res.end(JSON.stringify({ requests: 12345, errors: 2 }));
141
+ }
142
+ });
143
+
144
+ admin.add_endpoint({
145
+ path: '/api/admin/v1/metrics/reset',
146
+ role: 'admin_write',
147
+ handler: (req, res) => {
148
+ // reset metrics...
149
+ res.writeHead(200, { 'Content-Type': 'application/json' });
150
+ res.end(JSON.stringify({ ok: true }));
151
+ }
152
+ });
153
+ }
154
+
155
+ module.exports = my_admin_plugin;
156
+
157
+ // In your server.js:
158
+ server.admin_v1.use(require('./my_admin_plugin'));
159
+ ```
160
+
161
+ ---
162
+
163
+ ### `admin_v1.get_custom_sections()`
164
+
165
+ Returns the current list of registered custom section metadata.
166
+
167
+ ```javascript
168
+ const sections = server.admin_v1.get_custom_sections();
169
+ // [{ id: 'metrics', label: 'Metrics', icon: '📊', api_path: '/api/admin/v1/metrics' }]
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Declarative Configuration
175
+
176
+ Custom sections and endpoints can be declared in the `Server.serve()` options:
177
+
178
+ ```javascript
179
+ Server.serve({
180
+ Ctrl: MyControl,
181
+ port: 8080,
182
+ admin: {
183
+ sections: [
184
+ {
185
+ id: 'jobs',
186
+ label: 'Background Jobs',
187
+ icon: '⚙️',
188
+ api_path: '/api/admin/v1/jobs',
189
+ handler: (req, res) => {
190
+ res.writeHead(200, { 'Content-Type': 'application/json' });
191
+ res.end(JSON.stringify(get_job_status()));
192
+ }
193
+ }
194
+ ],
195
+ endpoints: [
196
+ {
197
+ path: '/api/admin/v1/jobs/trigger',
198
+ role: 'admin_write',
199
+ handler: (req, res) => {
200
+ trigger_job();
201
+ res.writeHead(200, { 'Content-Type': 'application/json' });
202
+ res.end(JSON.stringify({ ok: true }));
203
+ }
204
+ }
205
+ ]
206
+ }
207
+ });
208
+ ```
209
+
210
+ ---
211
+
212
+ ## Disabling the Admin UI
213
+
214
+ ```javascript
215
+ // Boolean shorthand
216
+ Server.serve({ Ctrl: MyControl, admin: false });
217
+
218
+ // Object form
219
+ Server.serve({ Ctrl: MyControl, admin: { enabled: false } });
220
+
221
+ // Constructor form
222
+ const server = new Server({ Ctrl: MyControl, admin: false });
223
+ ```
224
+
225
+ When disabled, no admin routes, SSE channel, or request instrumentation are set up. `server.admin_v1` is `null`.
226
+
227
+ ---
228
+
229
+ ## Exported Classes
230
+
231
+ For advanced use cases (custom auth, subclassing, testing), the admin classes are exported:
232
+
233
+ ```javascript
234
+ const Server = require('jsgui3-server');
235
+
236
+ // On the Server constructor:
237
+ const { Admin_Module_V1, Admin_Auth_Service, Admin_User_Store } = Server;
238
+
239
+ // From the npm module entry:
240
+ const jsgui = require('jsgui3-server');
241
+ const { Admin_Module_V1, Admin_Auth_Service, Admin_User_Store } = jsgui;
242
+ ```
243
+
244
+ ### Admin_Module_V1
245
+
246
+ The core admin adapter. Instruments the server, manages telemetry, provides APIs and SSE.
247
+
248
+ **Key properties:**
249
+ - `auth` — `Admin_Auth_Service` instance
250
+ - `user_store` — `Admin_User_Store` instance
251
+
252
+ **Key methods:**
253
+ - `init(server)` — Attach to a server instance
254
+ - `add_section(opts)` — Register custom sidebar section
255
+ - `add_endpoint(opts)` — Register custom API endpoint
256
+ - `use(plugin_fn)` — Apply a plugin function
257
+ - `get_custom_sections()` — Get section metadata array
258
+ - `get_status()` — Get server status snapshot
259
+ - `get_resources_tree()` — Get resource pool tree
260
+ - `get_routes_list()` — Get route registrations
261
+ - `destroy()` — Cleanup heartbeat and SSE
262
+
263
+ ### Admin_Auth_Service
264
+
265
+ Session-based authentication service.
266
+
267
+ **Key methods:**
268
+ - `is_authenticated(req)` — Check if request has a valid session
269
+ - `has_role(req, role)` — Check if session has a specific role
270
+ - `has_any_role(req, roles)` — Check if session has any of the given roles
271
+ - `create_session(username, roles)` — Create a new session
272
+ - `destroy_session(session_id)` — Remove a session
273
+ - `handle_login(req, res)` — HTTP login handler
274
+ - `handle_logout(req, res)` — HTTP logout handler
275
+ - `handle_session(req, res)` — HTTP session check handler
276
+
277
+ ### Admin_User_Store
278
+
279
+ In-memory user credential store using scrypt hashing.
280
+
281
+ **Key methods:**
282
+ - `add_user({ username, password, roles })` — Add a user (password is hashed)
283
+ - `verify_credentials(username, password)` — Verify credentials (returns `{ valid, user }`)
284
+ - `has_user(username)` — Check if user exists
285
+ - `get_user(username)` — Get user record (without password hash)
286
+
287
+ ---
288
+
289
+ ## Architecture Notes
290
+
291
+ ### How Custom Sections Work
292
+
293
+ 1. **Server-side:** `add_section()` stores metadata and optionally registers an API endpoint
294
+ 2. **Client-side:** On activation, the admin shell fetches `GET /api/admin/v1/custom-sections`
295
+ 3. **Dynamic nav:** Custom sections are added to the sidebar below a separator line
296
+ 4. **Data fetch:** When clicked, the shell fetches the section's `api_path`
297
+ 5. **Auto-render:** The response is rendered as a table, key-value panel, or text
298
+
299
+ On repeated metadata fetches, previously mounted custom section nav controls are removed before new ones are added. This keeps the sidebar free of duplicate custom entries.
300
+
301
+ ### Security Model
302
+
303
+ - All custom endpoints are wrapped with role-based guards automatically
304
+ - Unauthenticated → 401 JSON response
305
+ - Authenticated but missing role → 403 JSON response
306
+ - Session cookies are `httpOnly` with `SameSite=Lax`
307
+
308
+ ### Roles
309
+
310
+ | Role | Purpose |
311
+ |---------------|-------------------------------|
312
+ | `admin_read` | View dashboard data and sections |
313
+ | `admin_write` | Mutating operations (start/stop/restart) |
314
+
315
+ Default users get both roles. Custom user creation:
316
+
317
+ ```javascript
318
+ server.admin_v1.user_store.add_user({
319
+ username: 'viewer',
320
+ password: 'readonly123',
321
+ roles: ['admin_read']
322
+ });
323
+ ```
324
+
325
+ ---
326
+
327
+ ## Chaining Example
328
+
329
+ ```javascript
330
+ server.admin_v1
331
+ .add_section({ id: 'workers', label: 'Workers', api_path: '/api/admin/v1/workers', handler: workers_handler })
332
+ .add_section({ id: 'queues', label: 'Queues', api_path: '/api/admin/v1/queues', handler: queues_handler })
333
+ .add_endpoint({ path: '/api/admin/v1/workers/scale', role: 'admin_write', handler: scale_handler })
334
+ .use(require('./my-monitoring-plugin'));
335
+ ```
336
+
337
+ ---
338
+
339
+ ## Verification
340
+
341
+ Use the Admin UI interaction regression suite after extension changes that affect shell behavior:
342
+
343
+ ```bash
344
+ node tests/test-runner.js --test=admin-ui-jsgui-controls.test.js
345
+ ```
@@ -0,0 +1,122 @@
1
+ # Chapter 1 — Control Candidate Matrix and Findings
2
+
3
+ ## Purpose
4
+
5
+ Prioritize the control catalog for adaptive upgrades based on real impact:
6
+
7
+ - Structural risk on phone/tablet/orientation change
8
+ - Data density and interaction complexity
9
+ - Existing gap between desktop and touch behavior
10
+ - Reuse value as a pattern for other controls
11
+
12
+ ## Evidence Snapshot
13
+
14
+ Recent source-level review identified these concrete issues in key controls:
15
+
16
+ - `master_detail.js`: fixed two-column grid (`minmax(180px, 240px) 1fr`) with no layout-mode branch.
17
+ - `tabbed-panel.js`: horizontal tab strip is vulnerable to overflow in narrow widths.
18
+ - `split_pane.js`: pointer-oriented resize interaction with no touch-first fallback.
19
+ - `data_table.js`: large data surface with no responsive column-priority/card transformation strategy.
20
+ - `sidebar_nav.js`: manual collapse exists, but no environment-driven auto-collapse/morph.
21
+ - `Toolbar.js`: no overflow strategy for narrow widths.
22
+ - `modal.js`: static size variants only; no automatic phone full-screen mode.
23
+ - `form_container.js`: no adaptive multi-column to single-column strategy.
24
+ - `status_dashboard.js`: strongest baseline due to grid auto-fit, but no explicit density/layout-mode policy.
25
+
26
+ ## Tiering Criteria
27
+
28
+ ### Impact score (1-5)
29
+
30
+ - 5: Breaks or heavily degrades on common phone/tablet layouts
31
+ - 4: Usable but substantially reduced usability on touch/narrow layouts
32
+ - 3: Mostly usable; quality or accessibility debt
33
+ - 2: Minor adaptive polish only
34
+ - 1: Already adaptive enough through existing composition/tokens
35
+
36
+ ### Effort score (1-5)
37
+
38
+ - 5: Significant API and behavior changes across composition + interaction + tests
39
+ - 4: Medium-high code and test work
40
+ - 3: Moderate scoped update
41
+ - 2: Small targeted update
42
+ - 1: Minimal changes
43
+
44
+ ## Candidate Matrix
45
+
46
+ | Control | Impact | Effort | Priority | Why now |
47
+ |---|---:|---:|---|---|
48
+ | Master_Detail | 5 | 3 | Tier 1 | Canonical two-pane pattern; immediate phone pain; good first pattern anchor |
49
+ | Tabbed_Panel | 5 | 4 | Tier 1 | High usage + overflow + keyboard/touch adaptation needs |
50
+ | Split_Pane | 5 | 4 | Tier 1 | Pointer-first behavior conflicts with touch/mobile |
51
+ | Data_Table | 5 | 5 | Tier 1 | Highest value for admin UIs; biggest adaptation gap |
52
+ | Sidebar_Nav | 4 | 3 | Tier 2 | Shell-level navigation needs auto morphing |
53
+ | Form_Container | 4 | 3 | Tier 2 | Forms must adapt cleanly across orientation and width |
54
+ | Modal | 4 | 2 | Tier 2 | Quick high-value upgrade for phone usability |
55
+ | Toolbar | 4 | 3 | Tier 2 | Navigation/action density requires overflow strategy |
56
+ | Window / Window_Manager | 3 | 4 | Tier 3 | Desktop metaphor must degrade predictably on touch |
57
+ | Wizard | 3 | 2 | Tier 3 | Stepper strip and nav controls need mobile pattern |
58
+ | Status_Dashboard | 2 | 2 | Tier 4 | Mostly good; needs explicit density/mode tuning |
59
+ | Drawer | 2 | 2 | Tier 4 | Good baseline; mostly environment integration and polish |
60
+
61
+ ## Top Discoveries
62
+
63
+ ### Discovery A — the highest-value pattern is the two-pane morph
64
+
65
+ `Master_Detail`, `Split_Pane`, and many app-level shells all need the same adaptive morph:
66
+
67
+ - Desktop: dual pane
68
+ - Tablet portrait: primary + secondary as revealable overlay
69
+ - Phone: stacked flow or drawer/sheet secondary
70
+
71
+ This should be implemented once as a reusable adaptive region pattern and reused.
72
+
73
+ ### Discovery B — navigation controls need shared overflow/morph infrastructure
74
+
75
+ `Tabbed_Panel`, `Sidebar_Nav`, and `Toolbar` all face narrow-width overflow and touch navigation constraints.
76
+
77
+ Without shared helpers, each control will reinvent:
78
+
79
+ - overflow detection
80
+ - “more” bucket behavior
81
+ - focus order and ARIA preservation across morphs
82
+
83
+ ### Discovery C — Data_Table is both a control and a mode family
84
+
85
+ Treat `Data_Table` as a multi-mode control family:
86
+
87
+ - Desktop mode: full grid
88
+ - Tablet mode: reduced columns + optional detail pane
89
+ - Phone mode: list/card mode with row expansion
90
+
91
+ Trying to keep a single static grid shape across all modes will keep mobile quality low.
92
+
93
+ ## Layer Analysis (A/B/C/D)
94
+
95
+ Applying the four-layer model:
96
+
97
+ - Layer A (Domain): mostly unaffected; business data stays stable.
98
+ - Layer B (View Composition): major work in Tier 1 and Tier 2 controls.
99
+ - Layer C (Adaptive Resolution): requires consistent environment service usage.
100
+ - Layer D (Concrete Render): token/mode-attribute CSS work across most controls.
101
+
102
+ ## Model Placement Rules for This Program
103
+
104
+ For all upgrades in this book:
105
+
106
+ - `data.model`: business entities, user-intent preferences that are device-agnostic.
107
+ - `view.data.model`: resolved adaptive state (layout_mode, visible_columns, region presentation state).
108
+ - `view.model`: transient interaction state (open/closed, active tab index, temporary scroll/focus state).
109
+
110
+ Never persist runtime viewport-derived values as domain data.
111
+
112
+ ## Success Criteria for Candidate Selection
113
+
114
+ A control is ready for implementation when:
115
+
116
+ 1. Target mode behavior is specified for phone, tablet, desktop.
117
+ 2. State placement is mapped to model layers.
118
+ 3. CSS mode-attribute strategy is identified.
119
+ 4. P0/P1/P2 viewport assertions are defined.
120
+ 5. Regression impact on existing desktop behavior is bounded.
121
+
122
+ Next: Tier 1 playbooks with concrete upgrade recipes.