HR-ATS-Portal/Sync_write_request.md

87 lines
2.9 KiB
Markdown

# Email service — write read-status (`PATCH /sync/read-status/...`)
Copy everything below the line into any LLM session (or hand it to whoever owns the
email microservice) before implementing the write endpoint.
---
You are extending the **email microservice** that already exposes the read-status
delta and point-lookup APIs documented in `Sync_read.md`. Implement a **write**
path that marks a message read (or unread) in the signed-in user's Outlook mailbox
via Microsoft Graph. Mirror the existing `/sync/read-status/*` style exactly —
same bearer auth, same `:path` id handling, same response shape.
## Why we need this
The HR-ATS inbox app learns that a user opened a message before Outlook does.
Today that signal dies in our database: we have no Graph write permission and the
email service exposes no write endpoint. Without this PATCH, local mark-read and
Outlook drift permanently (and a later delta can even revert our flag).
## Requested contract
Mirror the existing read endpoints so both parse with one code path:
```
PATCH /sync/read-status/message/{id}
Authorization: Bearer <api token>
Content-Type: application/json
{ "isRead": true }
```
**200 response** — identical shape to `GET /sync/read-status/message/{id}`:
```jsonc
{
"id": "AAMk…",
"isRead": true,
"lastModifiedDateTime": "2026-08-07T10:14:52Z",
"subject": "Invoice #421"
}
```
Same `:path` converter for Graph ids that contain `/`, `+`, or `=`. Same bearer
auth as every other `/sync/*` route. Answer `401` until device-code sign-in
completes.
## Required behaviour
- **Idempotent.** Re-PATCHing `isRead: true` when already true is a no-op `200`
with the current record.
- **Must not advance or disturb the delta cursor.** This is a point write, not a
sync round. Cursor, watcher, and `/changes` buffer stay untouched.
- **404 `ErrorItemNotFound`** for unknown or deleted ids (same as the GET).
- **403 surfaced distinctly** if the Graph scope is missing, so callers can tell
"not permitted" from "not found".
## Graph scope prerequisite
Needs `Mail.ReadWrite`. The service currently signs in read-only. Treat upgrading
the consent / device-code scopes as an explicit product decision before shipping
the route — not an implementation footnote.
## Optional batch form
For bulk reconcile without N round-trips:
```
PATCH /sync/read-status/messages
{ "ids": ["AAMk…", "AAMk…"], "isRead": true }
```
Return a list of the same per-message records (or per-id errors). Nice-to-have;
the single-id PATCH is the hard requirement.
## What the caller will do with it
HR-ATS will enqueue one Taskiq task per human mark-read, retried via existing
smart-retry middleware. Expected volume is low (opens, not sweeps). After this
lands we will stop treating local-only mark-read as a known divergence.
## Out of scope for this request
- Changing the delta `/sync/read-status` contract
- Push / Graph change-notification subscriptions
- Writing any field other than `isRead`