SDP closes a resolved ticket on its own after 2 or 3 days, so watching
only Closed gave the ding days late. Each user can now pick which
statuses count as closed for the feed (feedStatuses, defaulting to
STATUS_NAMES). With Resolved picked, tickets are timed by resolved_time
so the automatic close later doesn't ding again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Any Zoho account can approve the client, and an outside account got a
session that returned the .env site, group and technician names.
ALLOWED_EMAIL_DOMAINS is now required: the callback refuses other
domains and revokes their token, and every API call re-checks it so
older cookies stop working. /api/names also makes the caller's token
read from SDP before returning the shared names.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each user's sites, groups, technicians, timing, weather location and
hidden panels/columns are saved by Zoho email in DATA_DIR, merged over
the .env defaults and validated on PUT /api/settings. /api/names
suggests names from recent tickets, and weather is cached per zip from a
fixed list of campuses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each user now signs in with their own Zoho account through the web
OAuth flow (Server-based Application client), and every SDP query runs
with that user's token. Nobody who reaches the page can see data
without signing in.
- auth.js: authorization URL, code exchange, token renewal, revoke and
user info, replacing the device-code flow.
- session.js: tokens kept in an AES-256-GCM encrypted, HttpOnly,
SameSite=Lax cookie keyed by SESSION_SECRET. The access token renews
when due, concurrent calls share one renewal, and sessions end after
SESSION_DAYS.
- routes.js: /auth/login, /auth/callback (state checked), /auth/logout
(revokes at Zoho); /api/session, /api/closed, /api/workload and
/api/weather all need a sign-in.
- The server is stateless. boardService.js, tokenStore.js, ADMIN_KEY
and data/token.json are gone. The page runs the checks itself and
keeps the closed feed, backfilling 12 hours on first load.
- tickets.js: the closed feed query pages, and SDP 401s are rethrown
so the user is signed out.
- server.js: PUBLIC_URL, trust proxy, security headers, /healthz.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>