# Data Handling & Logging

> What psLens stores, what it does not, how data is encrypted at rest and in transit, and what gets logged for audit.

---

LLMS index: [llms.txt](/llms.txt)

---

This page is for compliance reviewers and DPOs who need a precise answer to "what data does psLens hold, where, and for how long?", and for security teams checking encryption and audit-trail posture.

For PII handling, jump to [Personal Data (PII)](#pii-reality-check).

---

## 1. What psLens Stores

psLens persists three categories of data, all inside the customer's own dedicated instance. There is no shared multi-tenant backend.

|              Where               |                             What                              |                    Retention                    |                                         Notes                                          |
| -------------------------------- | ------------------------------------------------------------- | ----------------------------------------------- | -------------------------------------------------------------------------------------- |
| `/data/nats` (NATS JetStream KV) | Alert history                                                 | Rolling window (configurable; short by default) | Alerts are about *current* problems. History is for trend review, not long-term audit. |
| `/data/nats`                     | Report output (Markdown)                                      | 90 days                                         | So you can revisit past audit findings; configurable                                   |
| `/data/nats`                     | Recently-viewed objects per user                              | Session-scoped                                  | Navigation convenience; not an audit log                                               |
| `/data/nats`                     | Encrypted DB / SWS credentials                                | Until deleted                                   | AES-256-GCM, key from `PSLENS_MASTER_KEY` env var                                      |
| `/data/nats`                     | Auth sessions (if `auth.enabled`)                             | Up to 1 year TTL                                | See [Authentication & Access](/security/authentication-and-access/)              |
| `/data/projects`                 | Uploaded PS project archives (`.zip`)                         | Until deleted                                   | Used by Project Compare; you control the upload set                                    |
| `/app/config.yaml`               | Configuration (DB names, SWS endpoints, optional credentials) | Until you change it                             | Bind-mounted from your filesystem; secrets preferably via env vars                     |

That is the complete persistent footprint. Everything else (query results, page renders, search hits) is generated on demand and not written to disk.

---

## 2. What psLens Does NOT Store

- **PeopleSoft business data.** Employee records, payroll, financial transactions, HR data, customer records, journals, vouchers. None of it. Reports summarize at runtime and discard the raw rows.
- **Database passwords in cleartext** (when `PSLENS_MASTER_KEY` is set).
- **End-user passwords.** psLens uses magic-link or reverse-proxy SSO; there are no user passwords to store.
- **Logs on disk.** Logs go to stderr; your container runtime decides what to do with them.
- **Telemetry, analytics, or usage data shipped back to Cedar Hills Group.** psLens does not phone home.
- **Client-side cached data.** Nothing is cached in the browser. No writes to `LocalStorage`, `SessionStorage`, or `IndexedDB`; close the tab and there is nothing left.

---

## 3. Personal Data (PII) {#pii-reality-check}

The answer is more nuanced than "no PII".

**psLens does not *store* PeopleSoft user PII.** No persistent table or KV entry contains employee or operator records.

**psLens *does process* PeopleSoft user PII at request time.** When a user opens a search for Users, Operator IDs, or related security objects, psLens queries PeopleSoft, renders fields like `OPRID`, `OPRDEFNDESC`, `EMAILID`, and `EMPLID` in the browser, and discards the rows after the response. The data passes through psLens memory; it is not written to NATS, disk, or any log.

What this means for GDPR / CCPA / similar:

- psLens acts as a **processor** of this data while a query is in flight.
- The **controller** is the PeopleSoft owner (the customer).
- A DPA is available on request. See [Compliance & Vendor](/security/compliance-and-vendor/).
- Subject access / erasure requests are handled at the PeopleSoft source of record. psLens has nothing to delete because it has nothing persisted.

If your jurisdiction or policy requires that even transient processing be scoped, the `AuthorizedUsers` allowlist and the SWS table whitelist give you two layers of control over who can trigger such a query at all.

---

## 4. Encryption

### In transit

|                Hop                 |     Protocol     |                                                              Notes                                                              |
| ---------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Browser → psLens UI                | HTTPS            | Via your TLS pattern. See [Deployment Options](/docs/getting-started/deployment-options/) (6 options compared). |
| psLens → SWS endpoint              | HTTPS            | Basic-auth credentials never on the wire in clear                                                                               |
| psLens → SMTP (if magic-link auth) | SMTPS / STARTTLS | Configurable per your SMTP provider                                                                                             |

The SWS endpoint URL is HTTPS in every supported deployment. If you have a network where the PS server is reachable only over HTTP, raise it on the demo call. Running psLens over plaintext to PS is not a supported posture.

### At rest

|              Item               |                     Encryption                      |                                  Key source                                   |
| ------------------------------- | --------------------------------------------------- | ----------------------------------------------------------------------------- |
| SWS / DB credentials in NATS KV | AES-256-GCM                                         | `PSLENS_MASTER_KEY` env var (32 bytes, hex-encoded)                           |
| Auth sessions in NATS KV        | Opaque session IDs only; no secret material at rest | n/a                                                                           |
| Report output                   | Not encrypted (plain Markdown)                      | Stored on the customer-controlled volume                                      |
| Alert history                   | Not encrypted (alert metadata)                      | Stored on the customer-controlled volume                                      |
| Project archive uploads         | Not encrypted at application layer                  | Disk-level encryption (LUKS, fly.io volumes, EBS) is the recommended boundary |

**Master key management:**

- Required (and enforced at startup) when `PSLENS_ENV=production`.
- Stored as a 64-char hex string (32 raw bytes) in the `PSLENS_MASTER_KEY` env var. On fly.io: `fly secrets set PSLENS_MASTER_KEY=...`. In Docker Compose: `.env` file with `0600` permissions, or an external secret manager.
- **Back it up out of band.** Losing the master key means encrypted DB credentials in NATS KV become unreadable; you'd need to re-enter them.
- Rotation: generate a new key, re-encrypt the KV bucket on next start. Today this is a Cedar Hills Group-assisted operation; the self-service procedure is being documented.

---

## 5. Audit Logging

### What psLens logs today

|       Event        |          Where it goes           |                                           Includes                                           |
| ------------------ | -------------------------------- | -------------------------------------------------------------------------------------------- |
| Every HTTP request | stderr (structured slog)         | `X-Request-Id`, path, method, status, duration, authenticated user email (if `auth.enabled`) |
| Application errors | stderr (structured slog)         | Stack-relevant context, request ID for correlation                                           |
| Startup banner     | stderr                           | Version, commit SHA, build timestamp                                                         |
| Alert checker runs | stderr + NATS KV (alert history) | Which checker, what it found                                                                 |

The request ID flows through every log line tied to a request, so you can correlate a UI action to its server-side handler chain.

**Logs are written to stderr only.** psLens does not write logs to disk. Your container runtime decides what happens next: typically piped to your Docker logging driver, your systemd journal, your fly.io log stream, or your K8s log shipper. Send them to your SIEM via the same standard mechanism you use for any container workload.

### Where the *user-action* audit actually lives today

Because psLens is read-only, the question "who looked at what PS data, when" has its authoritative answer **on the PeopleSoft side**. The SWS framework logs every query it accepts, including the `OPRID` of the SWS service account, the SQL it ran, and the timestamp. That is the audit trail that matters for "did someone see employee X's record".

What psLens contributes:

- The HTTP request log (above) ties an authenticated psLens user to a specific page hit, and the page hit corresponds to a known set of SWS queries.
- Correlation across the two logs uses the request ID on the psLens side and the timestamp + query pattern on the SWS side.

### The gap and the roadmap

Today, **psLens does not write a structured per-user "action" audit log**. For example, `{user: alice, action: viewed, object: PSRECDEFN PS_VOUCHER, at: 2026-05-21T14:32Z}`. The HTTP request log is close to that but is operational logging, not an audit artifact.

**Roadmap:** add a first-class user-action audit log written to a NATS KV bucket with configurable retention, exportable to your SIEM. Targeted to land alongside native SSO. No committed date.

If a customer needs a richer audit story today, the recommended interim is: enable `auth.enabled`, ship the HTTP request log to your SIEM, and correlate with the SWS-side audit. Cedar Hills Group can help with the correlation queries.

### Retention

psLens retains structured logs only in your container runtime's log stream. Retention is whatever you configure there. No psLens-managed log retention policy exists; we deliberately stay out of that decision so it aligns with your existing log-retention SLAs.

---

## 6. What Reviewers Usually Ask

**"Where is the data physically?"** In your dedicated psLens instance. Managed deployments live in the fly.io region you choose at provisioning. Self-hosted: wherever you run the container. There is no shared backend.

**"Can you delete all data for a customer on request?"** Yes, by removing the deployment. Because all customer-specific state lives in the per-customer container's `/data` volume, deletion is `fly apps destroy` or `docker compose down --volumes`. There is no other location to scrub.

**"Do you encrypt the entire volume?"** Application-level encryption covers credentials. Volume-level encryption is the customer's choice. On fly.io, volumes are encrypted at rest by default; on your own infrastructure, use LUKS / EBS encryption / equivalent.

**"Do you have an SBOM?"** Available on request for any tagged build. See [Code & Supply Chain](/security/code-and-supply-chain/).

---

## Related

- [Code & Supply Chain](/security/code-and-supply-chain/). What's running in the code paths that touch data.
- [Authentication & Access](/security/authentication-and-access/). Session storage details.
- [Deployment & Operations](/security/deployment-and-operations/). Backup and restore for `/data/nats` and `/data/projects`.
- [Compliance & Vendor](/security/compliance-and-vendor/). DPA, sub-processors, residency.
