nx_legal_portal.nx
buildroot/runtime/nx_legal_portal.nx
about
nx_legal_portal.nx -- LEGAL RUNG D6: the Client Workspace portal request handler.
module: nishi-core.legal.portal
capability: LEGAL_PORTAL
The composition spine that ties the gated doc-signing logic cores into ONE
bytes-in/bytes-out HTTP request handler (the proven nx_status_daemon sd_handle
pattern): a thin socket loop can wrap it later, but the logic + the gate need
no socket and touch nothing live. It routes a tenant's requests over:
D1 nx_doc_vault -- a doc is served only if THIS tenant's vault owns it.
D2 nx_doc_envelope -- envelope list + status (signed N of M).
D3 nx_doc_serve -- open-in-app-of-choice document bytes.
D4 nx_doc_annotate -- the "what's still needed" checklist readiness.
D0 nx_legal_compliance-- the regime is SURFACED to the client: a REQUIRES_WET
instrument is told "e-sign not legally valid" rather
than silently offered for signing (never-void in UX).
nx_authz -- /portal (client level 1) vs /staff (lawyer level 2),
deny-by-default; an unlisted resource is 404.
Tenant isolation: one NxPortalCtx = one tenant's private stores, so a request
can never reach another tenant's envelopes/docs.
READ spine only -- the stateful POST mutations (sign/annotate) ARE the already-
gated logic cores (D2/D4); this organ is the routing + authz + serving layer
over them. Wiring it behind a live daemon (nx_andelinwest_daemon :8453) is a
separate, operator-gated deploy step.
Composes: nx_doc_envelope, nx_doc_serve, nx_doc_annotate, nx_doc_vault,
nx_legal_compliance. The /portal-vs-/staff level check is the same
longest-prefix deny-by-default rule as nx_authz, inlined here over two disjoint
prefixes to keep the compile unit lean. license_tier: ORIGINAL
lineage_id: nishi_legal_portal_d6
dependencies 6 imports · 6 importers
imports: nx_syscalls.nxnx_doc_envelope.nxnx_doc_serve.nxnx_doc_annotate.nxnx_doc_vault.nxnx_legal_compliance.nx
imported by: nx_legal_portal_boot.nxnx_legal_portal_boot_gate.nxnx_legal_portal_daemon.nxnx_legal_portal_gate.nxnx_legal_portal_live_gate.nxnx_legal_portal_post_gate.nx
structs
| 44 | struct NxPortalCtx |
consts
| 38 | const K_MAGIC_8192: i64 = 8192 |
| 39 | const K_MAGIC_1024: i64 = 1024 |
| 40 | const K_MAGIC_16384: i64 = 16384 |
functions
| 62 | func lp_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 63 | func lp_cat(out: *u8, o: i64, s: *u8) -> i64 { var k: i64 = 0; while s[k] != (0 as u8) { out[o] = s[k]; o = o + 1; k = k + 1 } return o } |
| 64 | func lp_num(out: *u8, o: i64, v: i64) -> i64 |
| 75 | func lp_eq(p: *u8, pl: i64, lit: *u8) -> i64 |
| 83 | func lp_prefix(p: *u8, pl: i64, lit: *u8) -> i64 |
| 91 | func lp_query_int(req: *u8, n: i64, key: *u8) -> i64 |
| 119 | func lp_text_response(out: *u8, status: *u8, body: *u8, body_len: i64) -> i64 |
| 132 | func lp_handle(pctx: *NxPortalCtx, req: *u8, n: i64, out: *u8) -> i64 called by 5: lp_serve_connlp_serve_conn_rwmainmainmain calls 17: sys_mmaplp_prefixlp_text_responselp_eqlp_catlp_num+11 |
| 241 | func lp_read_request(cfd: i64, buf: *u8, cap: i64) -> i64 |
| 265 | func lp_serve_conn(pctx: *NxPortalCtx, cfd: i64) -> i64 |
| 281 | func lp_pathlen(req: *u8, n: i64, pathbuf: *u8) -> i64 called by 1: lp_handle_post |
| 304 | func lp_handle_post(pctx: *NxPortalCtx, ncap: i64, req: *u8, n: i64, out: *u8) -> i64 called by 2: lp_serve_conn_rwmain calls 10: sys_mmaplp_pathlenlp_prefixlp_text_responselp_eqlp_query_int+4 |