This commit is contained in:
Skylar Grant 2026-10-15 16:53:51 -04:00
parent c75b5889cf
commit 1e3f8dc1ad
4 changed files with 157 additions and 0 deletions

40
CLAUDE.md Normal file
View File

@ -0,0 +1,40 @@
# CLAUDE.md
Context for Claude Code sessions in this repo. Keep this short. Longer notes live in `docs/`.
## Project
A help desk dashboard for ManageEngine ServiceDesk Plus Cloud (`ithelp.mainecc.edu`). It currently runs as a single Node/Express server. The central region (KVCC, EMCC, CMCC, MCCS) is configured through `.env`.
- **Goal:** multi-region, multi-user, customisable. See `docs/ROADMAP.md`.
- **Decisions, API gotchas and known issues:** `docs/NOTES.md`. Read it before touching any SDP query.
- **Latest session summary and handoff:** `SESSION.md`.
## Run
```text
npm install
npm run app # node src/server.js from the repo root; .env lives in the repo root
```
The app is served at <http://localhost:3000>. Sign in with the Connect button, which uses Zoho's device-code flow.
## Layout
- `src/server.js`: reads `.env` and starts everything.
- `src/auth.js`: Zoho device-code sign-in.
- `src/boardService.js`: token, state and refresh timers.
- `src/tickets.js`: all SDP queries (closed feed, status table, closed today, unassigned).
- `src/weather.js`: OpenWeatherMap, cached for 10 minutes.
- `src/routes.js`: the `/api/*` routes.
- `src/public/index.html`: the whole front end in one file (inline CSS and JS, no build step).
## Working agreements
- Never print or commit `.env` values (Zoho client secret, OpenWeatherMap key). Redact them when inspecting.
- There are no automated tests yet. Verify server logic by stubbing `axios.get`. Resolve axios from the project with `require.resolve('axios', { paths: [dir] })` so the stub hits the same instance. Verify the page by evaluating its `<script>` with stubbed `document` and `fetch`, or by taking a screenshot with headless Edge.
- The sandbox can't start a second server instance; it can't bind ports. Screenshots of the live app use the user's running server on port 3000.
- Match the existing style: 4-space indent and CommonJS on the server, 2-space indent in `index.html`, lowercase `//` comments explaining why rather than what. Some files have CRLF line endings, so use the Edit tool rather than sed for multi-line changes.
- Keep the core closed-ticket watcher (feed and ding) working and on by default.
- Don't commit unless asked. Commit messages end with the Co-Authored-By line for Claude.
- Record new decisions and gotchas in `docs/NOTES.md`, and move roadmap items as they're done.

53
SESSION.md Normal file
View File

@ -0,0 +1,53 @@
# Session summary: 2026-10-15
A Claude Code session that turned the closed-ticket board into a dashboard. Background is in `CLAUDE.md`, `docs/ROADMAP.md` and `docs/NOTES.md`.
## Where things stand
The dashboard is running and working against live SDP data for the central region. All the work below is in the working tree. The last few files (`CLAUDE.md`, `docs/`, `SESSION.md`) may still be uncommitted.
## What was built, in order
1. **Dashboard redesign** (`index.html`, `tickets.js`, `boardService.js`): stat tiles; a technician × status table with Total open and Closed today columns; the live closed feed in a side column; a "Sound on close" toggle, on by default; Refresh now. The table refreshes every `WORKLOAD_MINUTES` (default 5). The closed watcher still checks every minute.
2. **Central region scoping:** `SITE_NAMES` and `GROUP_NAMES` in `.env` are applied to every SDP query, and each ticket is also re-checked locally.
3. **Unassigned requests counter:** `UNASSIGNED_EXCLUDED_STATUSES` mirrors the ManageEngine "Central Region Unassigned" view. **Verified to match the view exactly.** The debug list is kept but hidden (`SHOW_UNASSIGNED_LIST = false` in `index.html`).
4. **Weather card** (`src/weather.js`, `/api/weather`): OpenWeatherMap current weather and 5-day forecast with icons, using `OWM_API_KEY` and `OWM_ZIP_CODE`, cached for 10 minutes. Working.
5. **Sign-in changes:** the Zoho page opens in a new tab, the button only appears once the device code exists, and the page checks quickly after Connect is clicked.
6. **Table layout:** totals moved to the left so they don't get cut off; the auth panel text is wider.
7. **SDP query fixes:**
- `greater_than` → `greater than`. The wrong spelling made SDP ignore all the criteria and return about 124k tickets.
- Paging now dedupes by ID and stops early when the total can't be reached.
- The "partial" note now names which query was cut off.
- **Verified fixed:** the "partial" note is gone.
8. **Small fixes:** `[hidden]` CSS bug (Refresh now showed when disconnected); a misplaced comment in `server.js`.
9. **README rewritten**, with new screenshots in `images/`. `1.png` and `2.png` are rendered with sample data; `4.png` is from the live server; `3.png` is unchanged.
10. **Credits:** page footer, README, `package.json` contributors, `server.js` header. Isaac Godin keeps the design credit.
11. **License:** MIT (LICENSE copyright Skylar Grant; package.json now says MIT, not ISC).
12. **Repo structure for working with Claude:** `CLAUDE.md`, `docs/ROADMAP.md`, `docs/NOTES.md`.
## Settings added to `.env` this session
`SITE_NAMES`, `GROUP_NAMES`, `UNASSIGNED_EXCLUDED_STATUSES`, `WORKLOAD_MINUTES` (optional), `OWM_API_KEY`, `OWM_ZIP_CODE`. All are documented in `src/env.example` and the README.
## Known issues
- **The Zoho token expires after about an hour and is lost on restart.** `auth.js` throws away the `refresh_token`. This is the first thing to fix before hosting.
- On a typical screen the status table scrolls sideways ("Need Info" gets cut off), because the page is capped at 1,320px.
- Anyone who can reach the URL can see the data and click Connect or Refresh. That's fine locally, not when hosted.
## Next steps
Planned direction: hosted, multi-region, per-user. See `docs/ROADMAP.md`.
1. **Phase 1:** store and auto-renew the refresh token, save it so it survives restarts, and make Connect and Refresh admin-only.
2. **Phase 2:** regions as configuration in SQLite, with the current `.env` settings as the first region, "Central", plus a region switcher.
3. Then user sign-in, admin pages and Docker.
**Answer these before phase 3:**
- Are regions a security boundary or a convenience?
- Microsoft or Zoho sign-in for staff?
- Does SDP restrict technicians to certain sites?
## To pick up
Start a Claude Code session in this repo and say something like: *"Read SESSION.md and docs/ROADMAP.md, then start phase 1."*

27
docs/NOTES.md Normal file
View File

@ -0,0 +1,27 @@
# Notes
## SDP v3 API gotchas
Docs: <https://www.manageengine.com/products/service-desk/sdpod-v3-api/getting-started/search-criteria.html>
- **Condition names have spaces:** `greater than`, `is not`, `lesser than`. `greater_than` isn't valid, and SDP silently ignored the **entire** search criteria because of it, returning every ticket (124,050). If a query's `total_count` is huge, suspect the criteria first.
- **Paging:** `row_count` is at most 100. Use `start_index`, and stop when `list_info.has_more_rows` is false. Ask for `get_total_count: true` on the first page. `getAllRequests` dedupes by ID and stops at 20 pages or when the total is unreachable.
- **Multiple values:** use a `values: [...]` array, and join criteria with `logical_operator: 'AND'` (see `allOf()` in `tickets.js`).
- **"Technician is empty":** written as `{ field: 'technician', condition: 'is' }` with no value. This isn't documented, since the docs only show the "is not" form, but it's verified to work.
- **Field names that work in filters:** `site.name`, `group.name`, `technician.name`, `status.name`, `last_updated_time`.
- **Group names:** the ManageEngine UI shows groups as "Customer Support « KVCC", but the API name is plain "Customer Support".
- **Sign-in scope:** `SDPOnDemand.requests.READ` is enough for everything so far.
- **Token lifetime:** Zoho access tokens last about an hour. Refresh tokens aren't stored yet (roadmap phase 1).
## Decisions
- **2026-10-15:** **MIT license.** Copyright Skylar Grant.
- **2026-10-15:** **OpenWeatherMap** for weather. The free tier covers current weather and the 5-day forecast, and results are cached for 10 minutes. The National Weather Service API was the alternative (free, no key), but it needs three calls per lookup.
- **2026-10-15:** **Unassigned counter** uses its own status exclusions (`UNASSIGNED_EXCLUDED_STATUSES`) to match the ManageEngine view. The debug list is kept but hidden (`SHOW_UNASSIGNED_LIST` in `index.html`).
- **2026-10-15:** **Multi-region approach:** one service token plus region config, not per-user Zoho tokens. A user's own token could see all 124k tickets, so it wouldn't separate regions, and per-user polling multiplies API traffic. See `ROADMAP.md`.
## Known issues
- The status table scrolls sideways once there are more statuses than fit, because the page is capped at 1,320px. Consider widening the page or narrowing the sidebar.
- All statuses not in `STATUS_NAMES` count as open, including "Need Information" and "On Hold". This is intentional for now; revisit when regions get their own config.
- The token is lost on restart and expires after about an hour.

37
docs/ROADMAP.md Normal file
View File

@ -0,0 +1,37 @@
# Roadmap
## Goal
A hosted dashboard where staff in each MCCS region sign in and see their own region's queue. It should be customisable per user, and easy to extend with new panels.
## Target architecture
- **Identity:** users sign in (Zoho web OAuth, or Microsoft if MCCS staff use it) only to identify themselves.
- **Data:** one service connection, signed in once by an admin, with its refresh token kept and auto-renewed. Its SDP account must be able to see every region.
- **Regions:** profiles stored in SQLite (sites, groups, technicians, statuses). Checks run once per region and the results are cached, so API traffic grows with regions, not viewers.
- **Access:** users are assigned to regions and the server enforces it. An admin role manages regions and assignments.
- **Extensibility:** each panel is a module with server code to fetch its data and page code to draw it. The weather card is the first example.
## Phases
- [ ] **1. Keep the token alive:** store the Zoho `refresh_token` (currently thrown away in `auth.js`), auto-renew the hourly access token, and save it to a file or the database so it survives restarts.
- [ ] **1b. Admin-only actions:** make `/api/connect` and `/api/check` admin-only.
- [ ] **2. Regions as configuration:** one board service per region, `/api/regions/:id/...` routes, and a region switcher on the page. The current `.env` settings become the first region, "Central".
- [ ] **3. User sign-in:** web OAuth, sessions, user-to-region mapping, admin role. Needs a "Server-based Application" client in the Zoho console and HTTPS on a real hostname.
- [ ] **4. Admin pages:** edit regions and assign users.
- [ ] **5. Deployment:** Dockerfile and docker-compose with `env_file: .env` and a volume for the database and token.
- [ ] **Later:** per-user preferences (default region, hidden columns, sound) and panel modules.
## Open questions
- Are regions a **security boundary** (staff can't see other regions) or a **convenience** (default view with a switcher)?
- Do MCCS staff sign in with Microsoft 365 or Entra ID? That decides between Zoho and Microsoft sign-in.
- Does SDP itself restrict technicians to certain sites? If it does, per-user tokens become an option.
## Done
- Dashboard: stat tiles, technician × status table, live closed feed with the ding.
- Central region scoping by site and group.
- Unassigned counter. Verified to match the ManageEngine "Central Region Unassigned" view on 2026-10-15.
- Weather card (OpenWeatherMap).
- Fixed SDP paging and the date filter (see `NOTES.md`).