Files

75 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ticket Scheduling Runbook (Schedule Entries)
End-to-end flow for "schedule my tickets on the calendar" requests, validated end-to-end on the VistaNet instance. All timestamps UTC.
## 1. Resolve the member
`/system/myMember` 404s for API members. Use `GET /system/members?conditions=identifier='SBrown'` (URL-encode quotes) → id. Reuse the id for every `owner/id` and `member/id` (SBrown = 147).
## 2. Pull open tickets
`GET /service/tickets?conditions=owner/id=<memberId> AND closedFlag=false&pageSize=1000`; filter client-side for truly-open (status starting `>`, name `Closed`, or `dateResolved` present ⇒ exclude). Handle both list and `{"tickets": [...]}` shapes.
## 3. Check SLA reality before doing SLA math
`GET /service/SLAs/{id}` tells you the plan exists. If `/service/SLAs/{id}/plans` returns EMPTY and `/service/slaPlans` returns 404, the SLA carries NO hour plans — Standard SLA (id 2) here has none, so every Priority 3–Medium ticket is SLA-identical and SLA contributes nothing to urgency. Do not invent response-time tiers from the SLA name. `/service/boards/{id}/slaVersions` and its `/detail` subpath also 404 on this instance — treat both as dead ends, not as a reason to stop ranking.
## 4. Rank by what changes a deadline
When priorities are uniform (all P3-Medium), rank from signals in the ticket data itself, in order:
1. Hard expiration dates in the summary (cert renewals: "Expiring on YYYY-MM-DD") — expired or expiring this week first.
2. Active security incidents and outages (summary words: intrusion, confirmed, outage, unreachable, failing) with status In Progress.
3. Client-flagged urgency ("Urgent per <name>").
4. Security hygiene (patching, key setup, directory sync, mail filtering).
5. User-facing breakage (Tier 3 Assigned).
6. Small tasks (new user setup) swept into slack blocks.
Do NOT cram project/coordination tickets (status `Must Schedule`) into gaps — they need client scheduling in long blocks; propose them for next week instead.
Unschedulable (list, don't book): On Hold, Waiting Client Response, Waiting parts/repair.
Status nuance: ticket status `Scheduled` only means SOME entry exists — often an all-day 0.0h placeholder months out. Check the entry's date against the summary expiry before trusting it.
## 5. Check existing commitments first
Fetch the week UNFILTERED — `dateStart > [Monday-local ISO] AND dateStart < [NextMonday-local ISO]`, pageSize 500 — and filter by `member.id`/`member.identifier` client-side. Member-scoped conditions on this endpoint intermittently drop or mutate entries. Retry until two consecutive fetches agree (a stability gate), never gate on an absolute entry count — entries legitimately vanish mid-session when other people edit the calendar. Compose around firm entries; anchor back-to-back rather than overlapping (overlaps ⇒ `400 InvalidObject` SystemConflict on dateStart). Note objectId-0 blocks (internal placeholders with no ticket behind them) and re-check commitments immediately before POSTing — the calendar can move between your fetch and your write.
## 6. Slot composition and dispositions
- Local (PDT = UTC-7) to UTC conversion: +7h (2:30p PDT → 21:30Z).
- Same-day urgent work goes TODAY in the first free block — an expiring cert waits for no one; start from the next half hour.
- Batch small tasks (≤1h each) contiguously on the lightest afternoon.
- Tickets whose start is gated externally (client confirmation pending, vendor scheduling unknown, still in evaluation) get NO entry — list them as dispositions with the blocking reason so nothing silently drops. Book when the gate clears. An ALREADY-BOOKED ticket whose gate moves later keeps its entry: reschedule via PATCH (§9), never delete+repost. A scheduling gate is recorded as an INTERNAL TICKET NOTE (§9), never in the entry `name` — a ticket-linked entry's display name auto-regenerates from `Company/Summary` and silently discards custom label text.
- Recurring unavailability: team/tech meeting every Friday 8:00–9:30 AM PDT — never schedule SBrown in that window, and never let a Friday block start before 9:30.
- After-hours work (evening server/RDS upgrades needing users logged off) gets a full evening block (e.g. 6–9p), not an afternoon gap fill, and needs a coordination runway — book the earliest evening the client could plausibly agree to, not tonight.
- Booking requests are literal id lists: book exactly the named tickets; a duplicated id means one booking plus a note, not two entries.
## 7. POST each entry
`POST /schedule/entries` with a plain JSON object (NOT JSON Patch):
```json
{
"name": "Company / Ticket# 12345 - short label",
"member": {"id": 147},
"type": {"id": 4},
"span": {"id": 1},
"status": {"id": 2},
"objectId": 12345,
"ticketType": "S",
"where": {"id": 4},
"dateStart": "2026-10-06T16:00:00Z",
"dateEnd": "2026-10-06T18:00:00Z",
"hours": 2.0,
"doneFlag": false,
"meetingFlag": false
}
```
Observed ids: span 1 = `N`, status 2 = `Firm`, type 4 = `S`, where 4 = `Remote`. `name` is the free-form calendar label.
## 8. Verify, then audit coverage
Re-GET the unfiltered week window and confirm each new entry by objectId AND intended start time; a 200 on the POST is not proof the calendar shows it. If a freshly posted entry is missing from the refetch, direct-GET the entry id: 404 ⇒ deleted/rolled back; present ⇒ transient list unreliability. Then audit the whole picture in the same pass: every open ticket with a summary expiration date vs its calendar coverage, every Must Schedule ticket vs entries, my timed entries pair-wise for overlaps, and next week's window for duplicate bookings of the same ticket. A vanished block usually means the ticket closed (`>Completed`), was reassigned (owner changed), or a duplicate was cleaned up — check ticket status/owner before treating absence as a scheduling failure.
Present results with local times, then a disposition list — booked / blocked-status (Waiting Client, On Hold, Waiting parts) / pending-external-gate / intentionally unbooked — plus flags: expired-but-waiting-on-client warnings, objectId-0 blocks with no ticket, and Must Schedule candidates for next week.
## 9. Modifying existing entries and recording gates
- **PATCH `/schedule/entries/{id}` requires a JSON Patch ARRAY** (same as tickets): `[{'op':'replace','path':'/dateStart','value':'...Z'},{'op':'replace','path':'/dateEnd','value':'...Z'},{'op':'replace','path':'/hours','value':3.0}]`. A plain JSON object 400s. A 200 does NOT prove every field took — re-GET and check each patched field.
- **Do not patch `/name` on a ticket-linked entry**: the write is accepted but the display name regenerates from `Company/Summary`, so any PENDING/DO-NOT-START marker in the label silently disappears. Skip it up front.
- **Scheduling gates live as internal ticket notes**: `POST /service/tickets/{id}/notes` with a PLAIN JSON object (notes are not JSON Patch): `{'text': '...', 'internalAnalysisFlag': true, 'processNotifications': false}`. State the window, the entry id, who must confirm, and DO-NOT-START until then. `customerFlag` is not a valid ServiceNote member on this version (400 if included).
- **Owner reassignment** (ticket leaves your queue): `[{'op':'replace','path':'/owner/id','value':<memberId>}]` on `/service/tickets/{id}`, then fresh-GET to verify owner identifier. Resolve the new member's id first with `GET /system/members?conditions=identifier='X'`. Remove the ticket from your scheduling plans the same turn — don't book/keep entries for tickets you no longer own.
- **Ownership hygiene check (standing rule)**: for a tech's open tickets whose most recent note is from another tech (a likely transfer), vet before PATCH: automation members (the API/service-account members) NEVER receive ownership — their notes are integration/alert noise; time entries count as "me being there" (older intake note beats nothing, loses to a newer TE by the current owner); read the note's intent — intake/directive notes ("please order and drop ship", "get you guys involved") keep the ticket with the current owner; when the current owner has NO note and NO TE and the other tech's note is newer, that's a legitimate transfer. Verify each PATCH with a fresh GET of owner.identifier; drop transferred tickets from any staged plan same turn.
## Next-week candidate review
When asked what could be scheduled next week: fetch next + far-week windows (stability-gated), subtract every open ticket that has a booking in them, list the remainder grouped as schedulable (with concrete proposed slots from actual gaps), conditional-on-gate, and parked — naming the gate per ticket. Next-week Mon–Wed is typically wide open; propose day+time anchors, not vague availability.