feat(portal): add service drawers and employee portal preview

This commit is contained in:
DeCentN2Madness committed 2026-10-30 00:03:21 -07:00
1 parent ff80ee516f
commit e97f0ea9b4
39 files changed
+1446 -130

No files matched your search

+29 -2
View File
@@ -1,9 +1,9 @@
# AIA Astro Migration — Living Session Handoff
**Last updated:** October 29, 2026 (UTC)
**Last updated:** October 30, 2026 (UTC)
**Repository:** `AIAMarketing/azinstitute4autism.com`
**Working branch:** `faithful-astro-migration`
**Last accepted technical implementation:** Phase 9 bounded landing-page integration (presentation and inactive lead UI only; human decisions and production activation pending)
**Last accepted technical implementation:** Phase 9 isolated consultation integration at `ff80ee516f0185023af1f29937e29dfb30d31f47`; this handoff also describes the consolidated service-drawer and employee-portal checkpoint candidate
**Previous accepted checkpoint:** P9-03 documentation, signed `537f9864a0a3d0806180cbeca909bf1d03200c6f`
**Implementation checkpoint:** the commit containing this handoff update; obtain its actual SHA from Git history after the user creates the signed commit.
**Next milestone:** continue Phase 9 owner decisions and authorized integration batches; then Phase 10 — Final QA/Cutover Readiness.
@@ -374,3 +374,30 @@ The old `.phase7-stage-paths.nul` is absent; do not recreate it.
The staging aid is for the user's host terminal only; never stage it or use a
broad Git add. The actual future checkpoint SHA comes from Git after the user
signs; do not amend merely to insert it here.
## Consolidated service drawers and portal checkpoint, 2026-10-30
This section supersedes earlier explicit-only drawer behavior. The checkpoint
containing this update adds four-second/50%-scroll consultation opening, one
shared 30-day localStorage expiry preference, manual override through the six
existing EN/ES service CTAs, and typed bilingual service introductions. The
Academy configuration is prepared without a new page. The fixed seven production
and separate nine consultation-test route lists remain unchanged. Consultation
indexing approval must explicitly be `false`.
The employee route now has a locked, local-decryption UI and a private owner-run
collection/rewrite utility. Real passphrases were unavailable: real portal
content/resource inventory and collection remain blocked pending the owner-run
step. Do not claim approximately 43 resources as a measured inventory. Do not
commit the original source, ciphertext, decrypted views or private resources.
`www/private/employee-portal/` is ignored and outside Astro public output.
The accepted Jotform CSS backup and reconciliation archives are unchanged.
SOPS/age/sops-nix preparation is inactive, with no generated production identity,
recipient, deployed module or server-access activation. Portal browser encryption
remains access friction; internal resources require separate server-enforced
staff/management authorization. See
[consolidated implementation and validation](phase-9-service-portal-consolidated-2026-10-30.md)
and [owner utility instructions](../integrations/employee-portal/README.md).
The actual checkpoint SHA is the commit containing this section; obtain it from
Git history. No push, deployment or cutover is authorized by this work.
@@ -153,3 +153,26 @@ This is **documentation only**. It must not change Phase 3A publication policy,
Phase 3B hreflang implementation, Astro routing, production access, forms,
analytics, or server configuration. It does not claim authentication,
HIPAA compliance, or release readiness.
## 2026-10-30 owner authorization and implementation addendum
The owner explicitly authorized the two-stream browser-encrypted compatibility
model for development, superseding the earlier implementation hold for that
bounded scope. Production authorization and server-side resource protection are
still unresolved. The new scoped EmployeePortal component preserves the existing
route/SEO policy, local password entry, HMAC verification before decryption,
locked/unavailable default and passive content rendering.
The read-only source is at
`/home/alice/projects/wrk/aia/local-archives/aia-employee-portal-hubspot-footer-source.txt`.
Its two-stream structure and algorithm were inspected without exposing ciphertext
or plaintext. Legitimate codes were not available to the agent. Real-view
fidelity and exact resource counts remain blocked, not accepted. No real document
was fetched or published. The owner-run migration utility performs private
collection and approved link rewriting/re-encryption; see
[private workflow instructions](../integrations/employee-portal/README.md).
SOPS/age/sops-nix templates are prepared but inactive. Encryption of deployment
secrets does not authorize public delivery of staff/management documents. The
[consolidated report](phase-9-service-portal-consolidated-2026-10-30.md) records
synthetic tests and the separate remaining owner/cutover gates.
+17
View File
@@ -4333,3 +4333,20 @@ The owner also authorized `/lp/early-intervention`. It is migrated independently
At the owner's request, added a simple five-link review index modeled on the publicly retrieved `https://astro.web3app.dev/` index (normal TLS). `src/pages/lp/[...review].astro` generates only `/lp`, only when `PUBLIC_ALLOW_INDEXING` is not `true`. It is explicitly labeled temporary/testing, always `noindex,nofollow`, absent from sitemap/hreflang and normal navigation, and links only to eligible local landing-page records. No submissions, scripts, tracking or external assets were added. Production/indexing-enabled output remains 127 routes; normal staging has 128, including this review utility. Indexing is a build gate, not access control: never deploy the staging artifact as a production release.
Build and link audit pass. Library regression coverage checks the exact five destinations, staging robots, sitemap exclusion and absence from the indexing-enabled build. Guarded Chromium checks at 320/1440px pass with visible keyboard focus, no overflow and all five local links returning 200; no external browser requests occurred. Screenshots and browser evidence are temporary at `/tmp/aia-campaign-browser-HdWNvy/`. Prior five-page integration evidence remains historical; the new offline reconciliation records the extra staging utility. Nothing was staged, committed or deployed.
## 2026-10-30 service and employee-portal development revision
Owner-authorized intentional deviations: service CTAs now say Request a
Consultation / Solicitar una consulta and progressively open authorized test
drawers; automatic timing is four seconds or half-page scroll with a shared
30-day dismissal preference. Service-specific bilingual copy replaces generic
introductions. The same page layout, slide-in treatment and iframe restrictions
remain. Live public read-only captures were cache-qualified editorial reference,
not a new clinical approval.
The metadata-only employee route now includes the source-backed Access Code
Required interface. Real encrypted views remain unavailable without private
owner input. A passive DOM renderer intentionally disallows executable markup,
remote media and embedded forms; real-view fidelity therefore needs owner review.
No internal resource was published. Full evidence and boundaries are in
[the consolidated report](phase-9-service-portal-consolidated-2026-10-30.md).
@@ -64,3 +64,16 @@ P9-01 through P9-10 remain **Pending decision**. No technical feasibility result
## Recommended checkpoint boundaries
Keep the existing Phase 9 implementation, audit tooling and reports as one owner-reviewed technical batch. If a signed checkpoint is requested, stage exact paths only after reviewing the final status and reports. Keep any subsequent host rehearsal, Jotform configuration, counter live adapter and measurement work in separately authorized commits.
## 2026-10-30 portal and secrets preparation addendum
The local portal compatibility implementation does not close P9-02 or P9-09.
The owner must supply legitimate codes privately to collect and classify legacy
resources, accept the two decrypted views, approve delivery per resource and
verify server-side staff/management separation. SOPS preparation is an inactive
[module and operational guide](../integrations/nixos/README.md), not deployed
infrastructure. Real age recipients, host topology, access policy, recovery and
runtime key provisioning remain pending. Do not copy `private/` into a release.
The artifact verifier now rejects private resource paths and portal ciphertext
from release artifacts. A local ciphertext preview is deliberately not a
releasable artifact. No site cutover authorization is implied.
@@ -76,3 +76,15 @@ Focused resolver/artifact/nonproduction tests passed **21/21**. The existing For
| Consultation isolated-test | 128 | 0 | 0 | 10 | 6 |
In the isolated artifact, ten static frames are the seven frozen contact/landing paths plus the three standalone consultation pages. The six service-drawer adapters retain an approved source only as deferred data until a visitor opens the dialog. The final normal staging build was restored: 128 `noindex,nofollow` pages, an empty sitemap, zero hreflang links and zero Form A frames. Link, image and blog audits reported 0 broken internal links, 0 missing mapped page images and 0 blog-audit failures.
## Later consolidated owner revision, 2026-10-30
The explicit-only drawer behavior above is the earlier checkpoint's historical
evidence. The subsequent consolidated pass replaces it with four-second/50%
automatic opening, global 30-day expiry-only suppression, existing CTA override
and bilingual service-specific introductory copy. Iframe sources remain deferred
until opening, which may now be automatic under the authorized test mode.
The production allowlist is unchanged. See the current
[consolidated report](phase-9-service-portal-consolidated-2026-10-30.md) for tests,
privacy boundaries and remaining owner acceptance. Historical test counts above
are not claims about the revised behavior.
@@ -0,0 +1,225 @@
# Consolidated service-drawer and employee-portal development
Date: 2026-10-30 UTC. Starting branch: `faithful-astro-migration`.
Starting HEAD: `ff80ee516f0185023af1f29937e29dfb30d31f47`.
Tracked tree and index were clean; only owner-provided `prompt.txt` was untracked.
This is a local development checkpoint, not production authorization.
## Service implementation
The six existing EN/ES ABA Therapy, Autism Evaluations and Learner Social Club
pages retain their URLs and consultation anchor destinations. Each existing
anchor now has an explicit service trigger and accurate consultation label.
Only an authorized isolated-test drawer intercepts ordinary anchor activation;
modified clicks and no-JavaScript/unauthorized builds preserve navigation.
No competing opener is added.
`service-inquiry.ts` owns four-second and half-scroll triggers, first-trigger-wins,
positive scroll-distance handling, restored/changed height, resize observation,
disposal, reduced-motion close, native dialog focus and close behavior. Competing
modal/field editing cancels an automatic opportunity without polling. Closing
stores one shared 30-day expiry timestamp, including manual-close renewals.
Invalid, expired and implausibly future values are ignored. Storage denial uses
memory for the current document; across full navigation suppression cannot be
guaranteed when storage is disabled or cleared. No service or entered value is
stored. Closing/reopening preserves the one deferred iframe and its data.
`service-inquiry.ts` does not modify Jotform or detect submissions. The local
preference is functional only. Service-specific EN/ES copy is centralized in
`data/service-inquiry.ts`, including an unpublished Academy configuration without
an invented route. ABA 18 months–8 years, Academy 2–6 and Social Club 8–17 are
kept distinct. No conditional diagnostic note, booking promise or preselection
is added. Existing evaluation-page body claims still need the separately tracked
clinical/editorial review; this pass changes CTAs and drawer copy only.
The separate nine-route consultation gate remains isolated-test only. A missing
or malformed indexing flag previously passed that consultation check; it now
requires explicit `PUBLIC_ALLOW_INDEXING=false`. The seven production-eligible
contact/landing paths are unchanged. Full test configuration:
```sh
PUBLIC_AIA_FORMS_MODE=isolated-test
PUBLIC_AIA_FORMS_ENVIRONMENT=isolated-test
PUBLIC_AIA_FORMS_ISOLATED_TEST_APPROVED=true
PUBLIC_AIA_FORMS_LIVE_APPROVED=false
PUBLIC_AIA_FORMS_CONSULTATION_TEST_APPROVED=true
PUBLIC_ALLOW_INDEXING=false
```
## Portal implementation and fidelity boundary
The scoped `EmployeePortal.astro` preserves the route, metadata/noindex, sitemap
exclusion and lack of hreflang. It provides the source-backed access-code UI,
local Enter/Unlock handling without a native submitting form, accessible feedback,
HMAC-before-decrypt compatibility, two-stream selection, focused passive content,
password clearing after unlock, refresh/BFCache relocking and no-JavaScript help.
No plaintext/code goes to a server, browser storage or URL.
The original source remains read-only outside Git. Structural inspection verified
two streams, PBKDF2-SHA256 200,000 iterations, AES-256-CBC and HMAC-SHA256 over
IV plus ciphertext, with 16-byte salt/IV and 32-byte MAC. No legitimate passphrase
was available. An independently constructed Node crypto fixture establishes
algorithm compatibility, but actual legacy decryption has not been performed.
Real content layout, categories, contacts and linked workflows remain unverified.
Passive DOM reconstruction preserves text, headings, lists, tables and safe
links. Scripts, handlers, inline CSS, media and embedded forms are not executed.
Any real-source reliance on removed markup requires review; visual parity is not
claimed. Shared-code ciphertext remains offline-guessable access friction,
not authentication or a compliance certification.
`portal-input.mjs` accepts only an explicit local-preview approval, isolated
role, false indexing and validated private ciphertext. Default, missing and
production-shaped builds remain unavailable. The release verifier rejects portal
ciphertext and private paths. No real ciphertext or resource is committed.
## Sanitized resource reconciliation
| Measure | Verified result |
|---|---|
| Original encrypted views | 2; structural metadata only |
| Total original /hubfs/ references | Unknown, decryption blocked |
| Distinct resources / duplicates | Unknown, not assumed to be 43 |
| Successfully downloaded real resources | 0 |
| Failed/unavailable resource downloads | Not tested; no decrypted URLs available |
| Public-approved resources | 0 approved by this task |
| Staff/internal and management/internal counts | Unknown pending decryption/classification |
| Unresolved resource classifications | All real inventory remains unreviewed; count unknown |
| Real links rewritten | 0 |
| Links awaiting protected destinations | Unknown pending inventory |
| Remaining HubSpot dependencies | Unresolved encrypted references; not declared migrated |
| SOPS/NixOS | Inactive template prepared; no real keys or deployment |
The owner-run utility extracts decrypted references in memory, deduplicates by
source URL, collects bounded HTTPS resources into ignored 0700 directories,
retains hashes/size/MIME/status in a private 0600 manifest, and defaults to
UNRESOLVED. It rejects unapproved redirects and executable/error responses.
Approved rewriting requires implemented/verified destinations and server access
control for internal files; it regenerates salts/IVs, verifies round trips and
keeps the original as rollback. No mapping is considered migrated merely because
a proposed URL exists. See [owner commands](../integrations/employee-portal/README.md).
## Source and infrastructure evidence
Read-only public source references on this date:
[ABA](https://www.azinstitute4autism.com/aba-therapy),
[evaluations](https://www.azinstitute4autism.com/autism-evaluations),
[Social Club](https://www.azinstitute4autism.com/learner-social-club),
[locked portal](https://www.azinstitute4autism.com/employee-portal).
These were cache-qualified text captures. No authenticated live view or private
source content was retrieved through the web tool. The owner-provided modal copy
is the current development authority; fluent review remains pending.
The existing development flake and deployment plan were inspected. The inactive
[NixOS guide](../integrations/nixos/README.md) cites current official SOPS/sops-nix
documentation. It separates deployment encryption, browser access friction and
server resource authorization. No host topology, real key/recipient or access
service is invented. The module is not imported, activated or deployed.
## Validation
`npm run check` passed across 149 Astro files with zero diagnostics. Sequential
core suites passed: Markdown 20/20, publication 33/33, SEO 35/35, Library 53/53,
routes 10/10, campaigns 11/11 and Phase 8 contrast 5/5. The combined current
Form A, nonproduction, artifact, drawer, crypto and resource tests passed 33/33;
the narrower final artifact/resource rerun passed 18/18. The inactive Nix module
also passed `nix-instantiate --parse`.
Mock, indexing-enabled, production-gated, isolated-test and final off/staging
builds passed the artifact verifier. The isolated artifact contains 128 HTML
routes, ten approved immediate Form A frames and six approved deferred drawer
frames. The production-gated artifact retains exactly the original seven Form A
frames. The final restored staging artifact contains 128 `noindex,nofollow`
routes, an empty sitemap, zero hreflang and zero Form A frames. Link, image and
blog audits each reported zero failures. `git diff --check` passed.
Guarded Chromium results:
- Revised service/portal runner: 39 checks, 28 screenshots, six EN/ES services
at 320/390/768/1440px, timer and scroll races, shared suppression, storage and
modal/editing failure cases, lifecycle reinitialization, and synthetic staff
and management portal unlocks. It intercepted 31 fixed Jotform GET attempts.
- Nine-placement consultation regression: 45 checks, 36 screenshots and one
held-request fallback check; 40 fixed Jotform GET attempts intercepted.
- Existing seven-placement Form A regression: 35 checks, 28 screenshots and
four fallback-state checks; 38 Form A GET attempts intercepted.
- Off-mode browser verification attempted no Jotform request and emitted no
Form A adapter.
The browser guards recorded attempted requests before fulfillment or blocking.
No non-GET/HEAD form request, Jotform submission, production API call, portal
password transfer, advertising request, analytics request or WebSocket was
transmitted. Child Form A responses were local fixtures; these runs do not prove
real Jotform application behavior. Portal fixtures used random synthetic codes
created in memory and were never written to Git.
Final ephemeral evidence is outside Git: revised service and synthetic portal
screenshots/ledger at `/tmp/aia-service-portal-uncmM3`, consultation regression
at `/tmp/aia-form-a-consultation-zMsmpB`, and the frozen seven-placement Form A
regression at `/tmp/aia-form-a-iframe-77duED`. The normal staging artifact was
restored last and passed with 128 routes, zero sitemap/hreflang/Form A frames and
zero active native form actions.
## Owner acceptance and cutover dependencies
1. On loopback isolated preview, open each EN/ES service page at 320, 390, 768 and
1440px. Verify four-second opening and (after clearing the functional preference)
half-scroll opening; dismiss, navigate across services/locales, verify suppression
and manual CTA reopening. Inspect real Form A errors, Submit reachability and
focus across the frame. Do not infer child application success from frame load.
2. Review provisional Spanish/service copy and real assistive-technology behavior.
3. Run the private collection utility with legitimate codes, review local manifest,
classify resources, resolve failed/redirected downloads and approve destinations.
4. Test real staff and management decryption with local ciphertext preview, inspect
sanitizer effects, links, responsive directories, keyboard and refresh behavior.
5. Supply actual NixOS topology and separate age recipients privately, approve
staff/management authorization and recovery, and verify delivery before rewriting.
6. Forms C, production consultation routes, portal access, protected document
serving and the overall site cutover all require separate authorization.
## Exact checkpoint file inventory
- `.gitignore`
- `www/.env.example`
- `www/integrations/employee-portal/README.md`
- `www/integrations/nixos/README.md`
- `www/integrations/nixos/portal-secrets.nix`
- `www/reports/SESSION_HANDOFF.md`
- `www/reports/employee-portal-migration-brief-2026-10-08.md`
- `www/reports/migration-summary.md`
- `www/reports/phase-10-technical-readiness-package-2026-10-22.md`
- `www/reports/phase-9-form-a-consultation-isolated-test-2026-10-29.md`
- `www/reports/phase-9-service-portal-consolidated-2026-10-30.md`
- `www/reports/phase-9-two-form-integration-specification-2026-10-28.md`
- `www/src/components/Button.astro`
- `www/src/components/JotformIframe.astro`
- `www/src/components/ServiceInquiryDrawer.astro`
- `www/src/components/pages/EmployeePortal.astro`
- `www/src/content/pages/en/aba-therapy.mdx`
- `www/src/content/pages/en/autism-evaluations.mdx`
- `www/src/content/pages/en/learner-social-club.mdx`
- `www/src/content/pages/es/aba-therapy.mdx`
- `www/src/content/pages/es/autism-evaluations.mdx`
- `www/src/content/pages/es/learner-social-club.mdx`
- `www/src/data/service-inquiry.ts`
- `www/src/layouts/PageLayout.astro`
- `www/src/scripts/employee-portal.ts`
- `www/src/scripts/service-inquiry.ts`
- `www/src/utils/drawer-preference.ts`
- `www/src/utils/form-integration.ts`
- `www/src/utils/portal-crypto.mjs`
- `www/src/utils/portal-input.mjs`
- `www/tools/employee-portal-migrate.mjs`
- `www/tools/jotform-consultation-browser.mjs`
- `www/tools/jotform-form-a.test.mjs`
- `www/tools/phase10-artifact-verify.mjs`
- `www/tools/phase10-artifact.test.mjs`
- `www/tools/portal-resources.mjs`
- `www/tools/seo.test.mjs`
- `www/tools/service-portal-browser.mjs`
- `www/tools/service-portal.test.mjs`
The owner-provided `prompt.txt` remains untracked and outside the checkpoint.
Private directories contain no collected real resources in this run. Protected
`merge-plan.md`, archived reconciliations and the accepted Jotform CSS backup
are untouched.
@@ -100,3 +100,26 @@ This decision does not close P9-01, P9-03, P9-05, P9-06, P9-07, P9-09 or P9-10.
The owner reports that the Form A `consultation` context and its conditional rules have been configured through the connected Jotform app. The repository now permits the nine matrix placements only when every isolated-test gate is present, including `PUBLIC_AIA_FORMS_CONSULTATION_TEST_APPROVED=true`. Three standalone pages load the fixed consultation URL immediately; six English/Spanish service drawers retain no iframe `src` until the visitor explicitly opens them. This does not change the frozen seven-route production allowlist.
The earlier version of this specification required a conditional Autism Diagnostic Evaluation explanation. That requirement is superseded: no conditional explanatory note is required in Form A or Astro. The historical decision is preserved by this dated addendum; the current contract is the client-advocate conversation described above.
## 2026-10-30 consolidated drawer behavior revision
The later owner prompt supersedes explicit-only opening for the six EN/ES
service drawers. Authorized consultation-test drawers now open after four seconds
or 50% of positive available page-scroll distance, whichever occurs first.
Opening consumes both automatic triggers. A different open modal or actively
edited field cancels that automatic opportunity without polling. Deferred
Jotform loading begins only when the drawer actually opens.
Dismissal stores only `aia:service-inquiry:auto-suppressed-until`, a first-party
expiry timestamp for 30 days shared across services and locales. Existing
consultation anchors are explicitly marked as drawer triggers; they bypass
suppression manually and retain their consultation-page href without JavaScript
or an authorized drawer. Closing renews the preference. It is not an audience,
tracking identifier, service-selection record or form-response store.
Centralized bilingual headings/introductions use provisional owner-supplied
service copy. The Academy service key has EN/ES copy for ages 2–6 but no route,
navigation change, new iframe allowance or publication entry. All original
seven production and nine isolated consultation placements remain unchanged.
No diagnostic conditional note or service preselection is introduced. The
clinical and fluent-language review gates remain open.