Work inbox
/work — one list of what came in, who is working on it and by when. Implements
WRK-001 … WRK-016.
Page: src/pages/work/WorkInbox.tsx · drawer: src/pages/work/WorkItemDrawer.tsx ·
data: src/services/workService.ts · routes: handleWork() in src/lib/api.ts.
What it shows, and what it does not own
The list holds two kinds of row, and the difference is the whole design (WRK-001):
| Row | Where its owner lives | On this page you can |
|---|---|---|
| Work item — an enquiry that arrived, one logged here, a typed task | WorkItem."assigneeId" |
claim, hand over, park, answer, finish, reopen |
| Booking correction | Booking."correctionOwnerId" |
see it; Open goes to the booking |
| Incident | Incident."ownerId" |
see it; Open goes to duty of care |
| Customer request | CustomerRequest."assignedToId" |
see it; Open goes to the request |
| Visa enquiry | VisaIntakeRequest."assignedToId" |
see it; Open goes to the visa intake queue |
| Inventory hold | InventoryHold."holderUserId" |
see it; Open goes to holds |
| Group you lead | TravelGroup."leadUserId" |
see it; Open goes to the group |
A projected row is never claimed or closed here, because that would create a second owner for one piece of work. Groups appear only inside 30 days of departure, so the list stays work rather than a catalogue.
Tabs
| Tab | Shows | Needs |
|---|---|---|
| My work | everything assigned to you, from all seven sources | work.view |
| Waiting to be picked up | unassigned rows; yours to claim where claimable | work.view |
| My queues | the queues you lead | work.view.queue |
| Everything | all work | work.view.all |
Filters: search, queue, channel, and Late only. The list is ordered by what is due soonest, and overdue rows are tinted.
The clock
Every time on this page is working time (WRK-004): Monday–Saturday 10:00–19:00 IST, less the Friday prayer break 12:30–14:00, less holidays. An enquiry that arrives at 22:00 is not late at 09:00 next morning.
Targets come from the channel it arrived by (WRK-003): WhatsApp 30 minutes, phone 60, website 120, email 240. Park it stops the clock while you wait on a customer, an embassy or another department, and asks who and why — waiting time is excluded from every figure (WRK-005).
Actions in the drawer
| Action | Needs | Notes |
|---|---|---|
| Claim | work.claim |
Atomic. Two people clicking at once: one gets it, the other is told it has gone |
| Hand over | work.assign, or you hold the job (with work.claim) |
Reason required. The due time never moves (WRK-011). Managers also see suggestions ranked by load (INT-003). A holder who hands a job on no longer sees it, and the drawer closes |
| Park / restart | work.claim |
Reason and who you are waiting on required |
| Record the first answer | work.claim |
This is what stops the response clock. Later notes are added the same way |
| Put it back | work.claim |
Reason required; the release stays on the record |
| Finish | work.close |
One line about what happened |
| Cancel | work.assign |
Cancelling is a manager's act, not the handler's |
| Reopen | work.reopen |
Keeps the original arrival and due time; the reopen is counted |
Log a job asks what kind of job it is, a title, detail, how it arrived, who asked, and — for any job — an optional due time and a priority (Urgent, High, Normal, Low). A due time becomes the job's target, so the scorecard measures it against that time. A typed task with no due time gets the internal target, 480 working minutes (WRK-018). Linking a task to a booking, customer, group or partner is done from the phone; the drawer then shows Open the booking (or customer, group, partner).
Who is told, and when
Every note below lands in the person's notifications (the bell at the top of every desktop page, and Notifications in the phone app), rings their phone, and is e-mailed to their company address. Opening it opens the job.
| When | Who | The note says |
|---|---|---|
| A job is given or handed to someone else | the new holder | New job for you: …, who gave it, the reason, the due time |
| A job is finished or cancelled | the person who gave it — not if they closed it themself | Finished: … or Cancelled: … and the closing line |
| About one working hour before the due time | the holder | Due soon: … |
| The due time | the holder | Overdue: … |
| 1.5× the job's target | the queue's lead(s) | Overdue in your queue: …, who holds it, how late |
| 2× the target | everyone with work.assign |
Overdue, twice its time: … |
| 24 working hours past due | everyone with work.view.all |
Overdue by a working day or more: … |
Claiming a job yourself tells nobody. "Who gave it" is whoever handed it to its last holder; for a job a routing rule gave out, the person who typed it. Rules: WRK-009 and WRK-018.
The reminders are counted in working time less time spent parked (WRK-004, WRK-005). A parked job gets no reminder until it is restarted. Each reminder comes once per job and due time. A job nobody holds gets no Due soon or Overdue note, but its queue lead still hears; when someone is given it, they are told it is late at the next check. The check runs every 15 minutes, so a reminder can be up to 15 minutes after the moment in the table, and the phone can ring up to five minutes after the note appears (at once when it came from your own hand-over or close). The e-mail copies can be switched off as a whole in Admin → Reminders → Automatic e-mails by category (Work); the notes and the phone are not switched off. How it runs, and how to check it: Work reminders.
Every one of these writes an event, and the drawer lists them under What happened. Those rows are never edited or deleted (WRK-015) — that ledger is what will make the performance figures in 19-performance.md checkable.
Routing: who gets each kind of job
Routing, at the top of the page, lists every kind of job and where new ones go (WRK-007):
- The pool: it waits until someone permitted claims it. This is the default.
- A named person: always to them. For example, visa document chasing goes to the visa desk.
- Someone with a role: to whoever holds that role and is least busy (fewest open jobs, then whoever was given work longest ago).
Everyone who can see the inbox can read the rules. Managers (work.assign) change them,
with a reason. A rule applies to jobs that arrive after it is set, including website
enquiries, WhatsApp and email. If the named person is inactive, or can't see the work
inbox, the job waits in the pool instead of going nowhere.
Queues: who works each queue, and who leads it
Queues, at the top of the page, lists every open queue with its members and leads
(WRK-013).
Everyone who can see the inbox can read it. A holder of work.queues.manage (CEO, GM) can:
- Add a person to a queue, as a member or the lead, with their weekly capacity
points (optional). A member must be able to take jobs from the inbox (
work.claim) and a lead must be able to see a queue's work (work.view.queue), with an active login that is not paused; anyone else is refused, and the screen offers each person only the roles they can hold. Otherwise someone who cannot take jobs could be a queue's only member and lock it. - Change someone's role or capacity. The day they joined stays.
- Take off someone, after a confirmation. They stop being part of the queue at once; the row is kept, shown greyed as Taken off this queue, and Bring back restores them from that day.
What it changes:
- The lead is told when one of the queue's jobs reaches 1.5× its target (Overdue in your queue, WRK-009). A queue can have more than one lead; each is told.
- My queues shows a queue to its leads only, once it has one. Before that, everyone with
work.view.queuesees it there. - Once a queue has any member, only its members can pick up its waiting jobs. A queue with
no members can be picked up by anyone with
work.claim. Holders ofwork.view.allstill see everything. - A member or lead whose login is switched off or paused no longer counts: if they were the only one, the queue opens to everyone again, so it is never locked to someone who cannot work.
- Members' e-mail addresses are shown only to holders of
work.queues.manage.
Every change is a database function that checks work.queues.manage itself, and every change
is in the audit log with the person who made it. Weekly capacity points are recorded; nothing
uses them yet.
What arrives by itself
Nobody has to log these (WRK-002):
| Arrival | Becomes | Due by | Answered when | Closed when |
|---|---|---|---|---|
| A new lead — the website form, or one entered on Leads | An enquiry in the Sales enquiries pool, typed by the lead's source (website, phone, walk-in, sub-agent, email, WhatsApp) | That channel's target | The lead moves on from New | The lead is converted, lost or closed |
| An email to info@alhudatravels.in (once installed) | A lead with source email, then an email enquiry in the pool. A reply in the same thread, or another email from the same sender while their enquiry is open, joins it | The email target (240 working minutes) | The lead moves on from New | The lead is converted, lost or closed |
| A WhatsApp message | One item per conversation — later messages join the open one | The WhatsApp target (30 working minutes) | Someone replies from the WhatsApp inbox | You close it here |
| With the WhatsApp menu on: Talk to the office, or a bank receipt sent after Pay balance | The same WhatsApp item, titled WhatsApp: asked for the office or WhatsApp: bank receipt sent | The WhatsApp target | Someone replies from the WhatsApp inbox | You close it here |
The item says what the enquiry is about ("Website enquiry — Umrah · 4 people"), never who: no name, phone or message text is copied onto it (WRK-012). Open the enquiry or Open the WhatsApp chat in the drawer takes you to the record.
With the WhatsApp menu on, a message the menu answered raises nothing — a booking enquiry made in the menu arrives as a WhatsApp lead instead (COMM-030, COMM-032).
A lead entered already converted, lost or closed raises nothing. Visa enquiries were already in the list as projected rows and are unchanged.
On the phone
Tasks in the staff app (Home → My work, More → Tasks) is the same inbox: the same database functions, the same permissions. What the phone shows:
| Tab | Shows | Needs |
|---|---|---|
| Mine | what I hold, late first, then due today, later, no due time | work.view |
| To pick up | the pool; Take it on a task | work.view; work.claim to take |
| Given by me | open tasks I typed that someone else holds or that wait in the pool | work.create |
| Team | the queues I lead, or everything for leadership | work.assign and work.view.queue / work.view.all |
Filters: Late (asked of the database), Due today and Urgent & high (worked out on the jobs loaded so far, which come due-soonest first).
A task opens its own screen with the details, why it exists, the linked record and
What happened. The buttons are the drawer's, shown only when the database would
allow them: take it, record the first answer or add a note, park it (who and why)
or start it again, hand over (to anyone, least busy first; managers see the load
suggestions on top), put it back, finish, cancel (work.assign), reopen
(work.reopen). On the phone, answering, parking and restarting are offered to the
job's holder or a manager only.
New task (work.create): title, details, who holds it (me by default, the pool,
or — with work.assign — a colleague), the due time (today 17:00, tomorrow 12:00,
in three days, or a date), the priority, and optionally the booking, customer, group
or partner it is about, found by number, code or name.
A row owned by another screen opens the phone's booking, group or visa screen when the person may open it. Incidents, customer requests and holds have no phone screen yet, and the card says they are on the desktop.
How fast it opens
The inbox is one request to the database, work_inbox_screen
(PRF-010): the first page of
the list and the queues, job types and channels the filter bar offers. Before, it made 10
requests, 4 one after another (about 1 s from Srinagar). It needs work.view, as before,
and the list is the same work_inbox_page answer. Opening an item in the drawer is still
its own request.
The paging bar under the list shows rows per page (25, 50 or 100), which items are on screen out of how many ("1–25 of 312") and first, previous, next and last page — even when they all fit on one page (UX-030).
Not built yet
Stated plainly, because a silent gap reads as if it works:
- Only info@alhudatravels.in receives email, and only once the capture is installed (runbook). Other addresses, and anything on alhuda.co.in, do not.
- No automatic acknowledgement is sent. The per-channel switch exists in
WorkChannelTarget."ackEnabled"; the sender does not (WRK-010). - Rows owned by another screen are not reminded. A late booking correction, incident, customer request, visa enquiry, group or hold is tinted late here, but nobody is told from the inbox (WRK-009). Only work items are reminded.
- The 1.5× reminder reaches nobody until a queue has a lead (WRK-013). Name one in Queues (above).
- Weekly capacity points are recorded but not used. Nothing yet compares a person's load with their capacity.
- A task has no checklist, does not repeat, and its due time cannot be changed after it is created.
- The web dialog cannot link a task to a record or give it to a person yet. The phone does both; on the web, hand it over from the drawer after creating it.
- Performance is on its own page: Performance. Monthly frozen figures and queue-lead team views are not built yet.
- Tour leaders and partners cannot receive work yet, although the data model allows it (WRK-008).
- Leave approvals are not in this list. Each source here is its own hand-written branch
of
work_inbox_page(20260926220000), not a generic item, so leave would mean rewriting that function. Leave approvals have their own list at/leave/approvals, a count on the Leave page and in-app notifications, and no sidebar badge (Leave). - The phone app has no Queues screen. Members and leads are named on the web.