UpdateStatus Workflow
Update job application status in both SeriousLetter and job-room.ch (ORP).
Trigger: "update job", "job status", "rejected by X", "got interview at X", ": "
---
## CRITICAL RULES
1. **NEVER ask for confirmation** - when user reports a status change, update both SL and ORP immediately
2. **ALWAYS update both systems** - SeriousLetter AND job-room.ch, every time
3. **Use ORP API, NOT UI clicks** - POST /_action/update-work-effort via page.evaluate(fetch())
4. **Full reference**: See `memory/orp-internal-api.md` for complete API docs
---
## Step 1: Update SeriousLetter
```
sl_search_jobs(q: "company name") # Find the job
sl_update_job(job_uuid, status: "rejected", rejected_date: "YYYY-MM-DD")
```
**Valid statuses:** opportunity, editing, applied, rejected, not_applying, outdated
---
## Step 2: Sync to ORP (Create Entry if Missing)
```
sl_jobroom_sync_job(job_uuid) # Creates ORP entry if it doesn't exist
```
This handles new entry creation. If the entry already exists, it skips (dedup).
---
## Step 3: Update ORP Status via API
Navigate to job-room.ch in Playwright (any page), then use internal API:
### 3a. Find the work effort
```javascript
await page.evaluate(async () => {
const token = sessionStorage.getItem('authenticationToken');
const userId = 'USER_ID'; // See known IDs below
const resp = await fetch(
`/onlineform-service/api/npa/_search/by-owner-user-id?userId=${userId}&_ng=ZGU=`,
{
headers: {
'Authorization': token,
'X-Requested-With': 'XMLHttpRequest',
'Accept': 'application/json'
}
}
);
const data = await resp.json();
const proof = data.content[0];
return proof.workEfforts.find(we =>
we.applyChannel.address.name.includes('COMPANY')
);
});
```
**Response structure:** `{ content: [{ id: proofId, workEfforts: [...] }] }`
- Access via `data.content[0].workEfforts` (NOT `data[0]` - it's NOT a plain array)
### 3b. Update status
```javascript
await page.evaluate(async (we) => {
const token = sessionStorage.getItem('authenticationToken');
const userId = 'USER_ID';
// Modify the existing payload - it's a FULL REPLACE
we.applyStatus = ['REJECTED']; // or ['EMPLOYED'], ['PENDING']
we.rejectionReason = 'Absage erhalten am DD.MM.YYYY';
const resp = await fetch(
`/onlineform-service/api/npa/_action/update-work-effort?userId=${userId}&_ng=ZGU=`,
{
method: 'POST',
headers: {
'Authorization': token,
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(we)
}
);
return { status: resp.status }; // 201 = success
}, workEffort);
```
---
## Known User IDs
| User | userId |
|------|--------|
| Matthias | `591489d5-0039-11f1-a99a-462689f09ec3` |
| Gina | `703d651c-0412-11f1-a99a-462689f09ec3` |
---
## ORP Status Values
| SL Status | ORP applyStatus | ORP rejectionReason |
|-----------|----------------|---------------------|
| rejected | `["REJECTED"]` | "Absage erhalten am DD.MM.YYYY" |
| applied | `["PENDING"]` | null |
| rejected + interview | `["REJECTED", "INTERVIEW"]` | reason text |
---
## Authentication Notes
- Token: `sessionStorage.getItem('authenticationToken')` - already includes auth prefix
- `_ng=ZGU=` is just `base64("de")` (language key), NOT a CSRF token
- Must run inside Playwright browser context - curl returns 401
- Token expires ~10h after login
---
## Status-Specific Actions
### Rejection
1. `sl_update_job(status: "rejected", rejected_date: today)`
2. `sl_jobroom_sync_job(job_uuid)` (ensure entry exists)
3. ORP API: set `applyStatus: ["REJECTED"]`, `rejectionReason: "Absage erhalten am DD.MM.YYYY"`
### Interview
1. `sl_update_job(interview_date: "YYYY-MM-DD")`
2. ORP API: add `"INTERVIEW"` to applyStatus array
### Applied (new application)
1. `sl_update_job(status: "applied", applied_date: today)`
2. `sl_jobroom_sync_job(job_uuid)` handles creation with PENDING status
---
**Last Updated:** 2026-03-17