161 lines
8.8 KiB
Markdown
161 lines
8.8 KiB
Markdown
# Employee portal compatibility and private migration
|
|
|
|
Recorded 2026-11-04. The clinical director accepted the collected, non-PHI
|
|
staff and management portal content and the interim shared-code presentation.
|
|
Browser-side decryption remains access friction rather than individual
|
|
authentication, revocation, a secure session, or a HIPAA determination.
|
|
|
|
## Approved production ciphertext
|
|
|
|
An indexing-enabled production build may include one owner-approved encrypted
|
|
two-stream payload when both of these non-public build inputs are set:
|
|
|
|
```sh
|
|
AIA_PORTAL_PRODUCTION_APPROVED=true
|
|
AIA_PORTAL_PRODUCTION_CIPHERTEXT_FILE=/absolute/private/employee-portal/approved-production-ciphertext.json
|
|
```
|
|
|
|
The build rejects missing, malformed, symlinked, oversized, wrong-mode, or
|
|
simultaneous local-preview/production inputs. It never decrypts the payload at
|
|
build time. `/employee-portal` remains noindex, sitemap-excluded and
|
|
hreflang-excluded. See [the deployment runbook](../nixos/deploy.md) for the
|
|
approved release and protected-resource installation commands.
|
|
|
|
## Source and private collection
|
|
|
|
Read-only legacy footer source:
|
|
`/home/alice/projects/wrk/aia/local-archives/aia-employee-portal-hubspot-footer-source.txt`.
|
|
The original stays outside Git as rollback evidence. No access code was available
|
|
to the agent. The exact resource count and real content compatibility remain
|
|
unverified. Do not infer the earlier approximate 43 links as a measured count.
|
|
|
|
From `www`, in the owner's private interactive terminal:
|
|
|
|
```sh
|
|
node tools/employee-portal-migrate.mjs collect \
|
|
/home/alice/projects/wrk/aia/local-archives/aia-employee-portal-hubspot-footer-source.txt
|
|
```
|
|
|
|
Enter each legitimate view code at its hidden prompt. Never place codes in
|
|
arguments, environment variables, shell history or reports. The utility checks
|
|
both streams, keeps plaintext in memory, and collects only referenced `/hubfs/`
|
|
resources from the verified source origin. Other origins require explicit
|
|
review/code allowlisting; redirects are bounded and never inherit credentials.
|
|
No Jotform, Google or other vendor forms are fetched.
|
|
|
|
Private output is `private/employee-portal/`: directories 0700, manifests and
|
|
binary resources 0600. This exact subtree is gitignored and outside Astro's
|
|
public directory. Filenames are SHA-256 hashes of source URLs, independently
|
|
verified by content hashes. The manifest retains original references, labels,
|
|
view membership, MIME, bytes, status and delivery/classification decisions.
|
|
All new resources default to UNRESOLVED. Publicly reachable does not mean public
|
|
approved. Resuming verifies an existing file's content hash; mismatches are not
|
|
overwritten. HTML error documents, executable responses, invalid known signatures,
|
|
redirects outside approved destinations and resources over 50 MiB are rejected.
|
|
The first pass allows only the verified site origin. If a legitimate `/hubfs/`
|
|
response redirects to a HubSpot CDN, inspect that exact HTTPS origin first, then
|
|
add its origin to the private manifest's `approvedOrigins` list and rerun. Never
|
|
approve a redirect based only on a failed download or a broadly shared vendor
|
|
domain. Failures remain private review items. The utility prints counts only.
|
|
|
|
Before every artifact transfer, verify that only `dist` is copied and that it
|
|
contains no private manifest, document or real ciphertext unless that ciphertext
|
|
has separately been authorized for the local preview. Never archive the whole
|
|
working directory as a deployable artifact.
|
|
|
|
## Approved rewriting
|
|
|
|
The owner classifies records as PUBLIC-APPROVED, STAFF-INTERNAL,
|
|
MANAGEMENT-INTERNAL or UNRESOLVED in the private manifest. Set `deliveryPath`,
|
|
`rewriteApproved`, `destinationImplemented`, `destinationVerified`, and (for
|
|
internal documents) `destinationAccessControlled` only with actual evidence.
|
|
The utility does not create those destinations or infer their approval.
|
|
|
|
```sh
|
|
node tools/employee-portal-migrate.mjs rewrite \
|
|
/home/alice/projects/wrk/aia/local-archives/aia-employee-portal-hubspot-footer-source.txt
|
|
```
|
|
|
|
It reauthenticates both views, changes approved quoted href/src attributes only,
|
|
preserves unrelated HTML/labels, and re-encrypts with fresh salts and IVs. It
|
|
verifies round-trip decryption and distinct codes before writing new ciphertext
|
|
with exclusive filenames. The original source is untouched. CSS/srcset mappings
|
|
require separate review and are rejected rather than silently rewritten.
|
|
Unresolved links retain their original destination as a recorded dependency,
|
|
not a claim of verified destination health. A changed manifest alone never
|
|
changes links in the encrypted stream.
|
|
|
|
## Local preview and content safety
|
|
|
|
Use a private ciphertext file generated by `collect` or `rewrite`:
|
|
|
|
```sh
|
|
AIA_PORTAL_LOCAL_PREVIEW_APPROVED=true \
|
|
AIA_PORTAL_CIPHERTEXT_FILE=/absolute/private/ciphertext-TIMESTAMP.json \
|
|
PUBLIC_AIA_FORMS_MODE=off PUBLIC_ALLOW_INDEXING=false \
|
|
npm run dev -- --host 127.0.0.1
|
|
```
|
|
|
|
The 2026-10-30 revision removes dependence on the retired Form A environment role. Form mode is independent; `off` above is optional for local testing and cannot grant portal approval. The page defaults to locked/unavailable without its own explicit approval and valid private input. Indexing
|
|
builds cannot include it. The codes never go to a server, storage or URL. No
|
|
native form submits; Enter and Unlock use local WebCrypto. Only the matching
|
|
stream is displayed; refresh or leaving the page locks it again.
|
|
|
|
The passive DOM renderer preserves headings, lists, text, tables and safe
|
|
HTTPS/mailto/tel links, with no referrer on links. It rejects scripts, inline
|
|
handlers, styles, media, embedded forms and unknown tags. Real portal markup
|
|
has not been decrypted or reviewed; any removed behavior must be reviewed with
|
|
the owner before claiming fidelity. It must not silently become arbitrary
|
|
script execution. No real encrypted stream or plaintext is in Git.
|
|
|
|
### Scoped presentation correction, 2026-10-30
|
|
|
|
The renderer now maps only `hs-button`, `content-button`, or
|
|
`portal-resource-button` anchor tokens, or exact inline AIA orange background
|
|
colors (`#ffbd59` / `#ff914d`), to the local `portal-resource-button` class.
|
|
It does not copy the original style or arbitrary classes. These are narrow
|
|
compatibility candidates, not a claim that encrypted real views have been
|
|
inspected. HTTPS/mailto/tel links retain the existing safe URL checks; contact
|
|
links receive a local dark-orange accent for readable contrast. Table scope
|
|
and bounded numeric row/column spans are preserved. All other executable or
|
|
unapproved attributes remain removed.
|
|
|
|
The follow-up styling correction recognizes the live portal's `Daily Lineup
|
|
Report` and `Monthly Lineup Report` link labels, even when their original
|
|
HubSpot classes or inline fills are absent. It maps only those links to the
|
|
existing orange resource-button style; arbitrary anchors remain ordinary links.
|
|
Both unlocked views now use the site's orange accent for list-item markers.
|
|
The source classes and styles still do not reach the passive DOM.
|
|
|
|
### Staff resources and Management Templates, 2026-11-01
|
|
|
|
The owner observed that the non-management (general-staff) portal still lost
|
|
HubSpot's resource-button presentation. After **sanitizing** the decrypted DOM,
|
|
a headed `Management Templates` section identifies the general-staff resource
|
|
view. Valid HTTP(S) resource links in that view receive only the local
|
|
`portal-resource-button` class; `mailto:` and `tel:` retain contact-link
|
|
styling. Neither destination validation nor removed legacy classes/styles,
|
|
scripts, media or HTML attributes are relaxed.
|
|
|
|
The `Management Templates` unordered list receives a local
|
|
`portal-template-grid` class: two columns at desktop widths (768px+),
|
|
one column on smaller screens. Semantic list order and keyboard tab order
|
|
are retained, with responsive full-width buttons. This is a presentation
|
|
change only: it does not infer or approve employee resource access.
|
|
Synthetic staff/management browser fixtures check the distinction and
|
|
responsive columns. The actual decrypted staff source remains private;
|
|
owner should confirm layout and links in the local preview before merging.
|
|
|
|
Scoped typography, spacing, lists, table rules and keyboard focus apply to both
|
|
unlocked streams. Synthetic staff/management fixtures exercise these mappings
|
|
at 320/390/768/1440px. Owner must inspect the real views privately to confirm
|
|
legacy button recognition and source fidelity; if a different class is used,
|
|
provide sanitized class semantics rather than decrypted content or credentials.
|
|
|
|
Before owner acceptance: validate two real view codes privately, inspect every
|
|
resource/category, responsive directories, focus, link semantics and sanitization
|
|
impact. Check wrong-code feedback, keyboard unlock, no-JS explanation and refresh.
|
|
Production must use a separately reviewed runtime ciphertext delivery mechanism;
|
|
this batch intentionally provides only a gated local build input. Browser-delivered
|
|
ciphertext is publicly downloadable by anyone able to reach that preview.
|