Employee Portal — as-built documentationArchitecture · security · integrations · inventories generated from the source · runbook · generated

How the TJFACT Employee Portal is built — as deployed.

The handoff record for whoever runs the portal after Paint Your Heaven: what the pieces are, where they live, how access is decided, what talks to what, and the exact commands to keep it healthy. The inventories on the Modules, Roles, Lists, Routes, Configuration and Pages tabs are generated from the deployed source (not typed), so they cannot drift from the running build. No credentials, personal data or controlled information appear here.

Architecture

One host, three moving parts: a reverse proxy, a static page, and a Python service that owns state and every integration.

Browser

/prototype — the portal, one self-contained HTML file (all CSS and JS inline); renders what the session’s modules allow
/delivered · /guides · /asbuilt — handoff pages, gated by the same sign-in
Careers — the public job board (open module)
Microsoft sign-in redirect → /gov/auth/login → back to the page you asked for

Host (Caddy → service)

Caddy terminates TLS and serves the static files from /opt/hbf/caddy/site/tjfact/; /x → x.html
/gov/* is proxied to the Python service on 127.0.0.1:8791 (/gov stripped)
Service: /opt/hbf/tjfact/tjfact-config.py, systemd unit tjfact-config, standard library only — no framework, no database server
State: /opt/hbf/tjfact/ — configuration + 60 revisions of history, lists with per-row history, HR files, sessions key, admin token, audit log

Systems the service talks to

Microsoft Entra / Graph — sign-in, groups → roles, OneDrive & SharePoint files, mail from department mailboxes, Teams digest, directory import
UKG Pro — web services + REST: workforce, jobs, org levels → directory fill; probe & coverage
Deltek Costpoint — read-only bridge: report exports on OneDrive today; GET-only REST when the service account exists
SAM.gov · USAspending — opportunity feed, recompete radar (server key, shared cache)
AI vendor for Dash — OpenAI (GPT-6 Astra, fallback Sol) or Anthropic, server-side key, rate-limited, CUI-flagged

Everything the browser needs comes from the same origin. The page never holds a secret: keys and passwords live in the service’s configuration as write-only fields, the browser learns only that one is set.

Security posture

How access is decided, and what stops a mistake becoming an incident
IdentityMicrosoft Entra sign-in (OAuth code flow, signed state). Sessions are HMAC-signed cookies (tjs, HttpOnly, SameSite=Lax, Secure), 12 hours. Terminated in the HR directory = refused outright.
AuthorisationRoles carry modules (73, in 10 groups). Every list read/add/write, every config row and every route is gated server-side by module; the page only hides what the server would refuse anyway. Employee-facing intake lists accept adds from anyone signed in; only the owning module reads the queue.
AdministrationSuper admin is a locked role; roles and people are edited on the Admin dashboard with a change log. A separate admin token (file on the host, never in the page) is required for direct deploys and unlocks everything for operations; rotating it is a runbook step. A deploy can also be staged with no token: the staged file changes nothing until a super admin approves it on Admin → Deploys waiting for you.
SecretsConfiguration fields that look like credentials are moved to the secret store even if submitted as public; they are never returned to a browser. Probe output is scrubbed of key material before it is sent.
WritesSame-site check on browser writes; per-IP rate limits (saves, probes, AI, deploys); size caps per body, per row (16 KB) and per list (1,500 rows); every configuration save snapshots the previous revision and appends an audit line (who, row, fields).
Controlled informationBy TJFACT’s 18 Sep decision, CUI/CMMC material never enters the portal. Documents are scanned for markings on read and held; two Deployment Ops boards stay out; Dash flags controlled markings; the Admin → CUI compliance path page records the position.
Deploy safetyOnly allow-listed targets; content must hash to the declared sha256; Python must compile; previous version kept; one-call rollback. Training media uploads in verified parts. A staged deploy is checked when it is staged and again when a super admin approves it (hash, and compile for the service); at most 20 wait at once and staging is rate-limited.
CostpointThe bridge has no write path: every call is a GET; HTTPS only; per-read errors are named; credentials never leave the server.

Integrations

What each connection does, how it authenticates, and where it is configured
SystemUsed forConfigured on
Microsoft Entra IDSign-in; Portal-* groups → roles; app-only Graph token for the serverChecklist → Microsoft 365 → Entra row (admin-only)
Microsoft GraphOneDrive/SharePoint reads (documents, Finance report exports, budgets, the Costpoint training guides folder read through its sharing link and streamed to each reader), department mailboxes (offers, invites, reminders), Teams digest, directory importEntra row + M365 rows (sites, mail, Teams)
UKG ProWorkforce, jobs and org-level tables → directory fill; coverage probe; onboarding deep linksChecklist → External systems → UKG
Deltek CostpointCash / AR / AP / funding / timesheets — report route (OneDrive exports) now; GET-only REST route when a read-only service account is savedChecklist → External systems → Costpoint (admin-only)
SAM.govOpportunity feed and notice search for TJFACT’s NAICS codes; shared server cacheChecklist → BD → SAM.gov key
USAspendingRecompete radar (expiring awards, incumbents); no keyChecklist → BD → Recompete
AI vendor (Dash)Chat, extraction, analysis notes. OpenAI GPT-6 Astra with Sol fallback, or Anthropic; no completion cap; retries; live status probeChecklist → Dash row (admin-only)
GovWin IQBuilt for either decision on the subscription, and the two halves are independent. Without GovWin the BD Suite covers the same market research in house from live public data (SAM.gov, USASpending, FPDS) with no seat licences. With GovWin it is worked inside the intranet, with no outward links: every tracked opportunity has a full record on the BD page (all mapped fields plus the export's unmapped columns, editable, stored on the capture pipeline row and keyed on the GovWin #), filled by importing a GovWin xlsx/CSV export. The Web Services API (paid add-on) refreshes the tracked list every ten minutes and adds each opportunity's contacts and documents; read-only towards GovWin by Deltek's designChecklist → External systems → GovWin

Prepared by Paint Your Heaven LLC for TJFACT LLC. Inventories generated from the deployed source at . Nothing here carries credentials, personal data or controlled information.