sdp-request-watcher/docs/SESSION.md
Skylar Grant 3e41565ac1 Add security document and move session notes into docs
docs/SECURITY.md covers the layers of protection, what is stored, third
parties, limits and open items to investigate. SESSION.md moves to docs/
and is rewritten as the handoff for removing ticket subjects next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 21:45:46 -04:00

7.1 KiB

Session summary: 2026-10-15 (v2.1.0)

A Claude Code session that added per-user settings, closed a sign-in gap, and wrote the security document. Background is in CLAUDE.md, docs/ROADMAP.md, docs/NOTES.md and docs/SECURITY.md.

Where things stand

  • v2.0.0 (per-user Zoho sign-in, Docker) is running in production.
  • Branch v2.1.0 is pushed with four commits on top of v2.0.0, and tagged v2.1.0-prod-hotfix (2f137af). The tag starts the Gitea image build. The build and the production deploy haven't been confirmed.
  • Since that tag, these changes are not committed: SECURITY.md and SESSION.md moved into docs/, the open items section in docs/SECURITY.md, and the doc links in CLAUDE.md and the README.

Before deploying v2.1.0 on the VPS

  1. Add ALLOWED_EMAIL_DOMAINS=mainecc.edu (plus any campus domains staff use) to the production .env. The server won't start without it.
  2. Add the sdp-data:/app/data volume to the compose file (on the service, plus the top-level volumes:), as in the repo's docker-compose.yml. Without it, saved settings are lost each time the container restarts.
  3. docker compose pull && docker compose up -d, then check:
    • an MCCS account signs in and gets the setup prompt
    • a personal Zoho account is sent back with "not allowed"

What this session did

Per-user settings (commits 9479b12, 53c519e, 817fa47)

  • ⚙ Settings button, and a setup prompt on someone's first visit (Save, or Use the defaults).

  • Settings per user:

    • sites, groups and technicians, entered as tags with name suggestions; typing any name still works
    • how often the status table recounts (2 to 60 minutes) and how long the feed lasts (1 to 24 hours)
    • weather location, from the campus list in src/places.js
    • hidden panels (stat tiles, weather, feed) and hidden status columns

    The ding plays even with the feed hidden. Statuses and sound aren't per user.

  • Storage: on the server in DATA_DIR/settings.json, keyed by the lowercased Zoho email, so settings follow people between browsers. Only values that differ from .env are stored. This replaced the planned localStorage design, and the container now needs a volume (/app/data in Docker).

  • Name suggestions (/api/names, src/names.js): one region-wide query of recent tickets (30 days, up to 500 tickets, names only). It's refreshed at most hourly, shared by all users, and kept in DATA_DIR/names.json. No new Zoho scope was needed. A typed name that differs from SDP's only in case is saved with SDP's spelling.

  • Server side:

    • The server reads each user's settings itself; the page doesn't send them with each call.
    • PUT and DELETE /api/settings validate everything (LIMITS in src/settings.js).
    • Weather is cached per zip.
    • The closed feed's hard-coded 12-hour cut-off was removed, since the feed length is now a setting.

Sign-in limited to email domains (commit 2f137af)

  • The gap: any Zoho account can approve our client. An outside account got a session, and /api/session gave it the .env site, group and technician names. Production v2.0.0 still has this gap until v2.1.0 is deployed.
  • The fix: ALLOWED_EMAIL_DOMAINS is required.
    • The callback refuses other domains and revokes their Zoho token.
    • requireSession checks the domain again on every call, so older cookies stop working.
    • Matching is exact, so lookalike domains are refused.
  • /api/names now makes the caller's own token read one row from SDP before it returns the shared names.

Documents

  • docs/SECURITY.md, written for MCCS IT leadership and reviewers. It covers each layer of protection, what is stored, third parties, the limits, 12 open items to investigate, and how everything was tested.
  • The README, env.example, NOTES.md (decisions) and ROADMAP.md were updated as each piece landed.

Verified

  • Server, end to end over a unix socket with axios stubbed:
    • defaults and the first-visit state
    • name suggestions: the region-wide query, the cache, and the access check before the cache is served
    • validation of every field, non-JSON bodies, and malformed JSON
    • saving: only values that differ from the defaults are stored, and names take SDP's spelling
    • the closed and workload queries use the saved region and feed length
    • weather per zip
    • reset, and saved settings surviving a restart
    • the domain check: outside, lookalike and missing emails, a second allowed domain, an outsider's pre-existing cookie, and startup without the setting
  • Page, in jsdom with stubbed fetch:
    • the setup prompt, and suggestions leaving out names already chosen
    • tag adding and removal, Enter, Backspace, and a typed but un-added name counting on save
    • a server error shown inside the dialog, and the save body
    • after a save: the feed restarting, the recount, the weather reloading, and hidden panels and columns
    • reset, and the full-width layout
  • Not verified:
    • anything against real SDP or Zoho
    • how the dialog looks; there's no Chrome or Edge on the dev Mac for a screenshot
    • the Gitea build of the hotfix tag

Next steps

  1. Remove ticket subjects (first thing tomorrow). Ticket subjects can name students or describe their situation, which is a FERPA risk. They reach the page in two places:

    • Closed feed: fetchClosedTickets in src/tickets.js requests subject and returns it. The page shows it in renderTicket in src/public/index.html.
    • Unassigned list: fetchUnassigned requests subject and returns it. The page shows it in renderUnassignedList, the hidden debug list.

    Drop subject from fields_required and from the returned objects, so it never leaves SDP, and update both render functions. The server never writes subjects to disk; they only pass through memory and the page. Afterwards, update docs/SECURITY.md (the page section, and open item 1) and docs/NOTES.md.

  2. Technician check at sign-in (the ROADMAP item). Ask SDP whether the signed-in user is a technician. That probably needs a users or technicians read scope; confirm the exact scope name and endpoint in Zoho's docs. A new scope means everyone signs in again. It would also allow real pick lists for technicians.

  3. Commit the document moves and the open items.

  4. Deploy v2.1.0, following the checklist above. Then try it live: the quality of the name suggestions, the setup prompt, and the volume surviving a pull and up -d.

  5. Work through the open items in docs/SECURITY.md, starting with MCCS IT approval for the hosting and the non-technician test.

  6. Carried over from earlier sessions:

    • check that the token renews after an hour
    • README screenshots
    • links to Zoho's documentation for the web sign-in flow
    • the status table scrolling sideways (see NOTES.md)
    • fill in campus satellites and confirm the zip codes in src/places.js

To pick up

Start a Claude Code session in this repo and say something like:

Read docs/SESSION.md and docs/SECURITY.md. First, remove ticket subjects from everything the server requests and the page shows (FERPA). Then we'll add the SDP technician check at sign-in.