AKS Anvil

Civic Desk notes

Dual-role civic UX on one shared store

Civic Desk is a local educational demo of how citizen-facing complaint submission and staff-facing triage can share one datastore — including priority, department assign, internal notes, an offline map pin, up to three photos in IndexedDB, named templates, in-page notifications. It is not a production 311 system, not connected to any municipality, and not a substitute for official channels.

Last updated 25 August 2026

1. Two apps, one desk

Real municipalities often ship separate citizen portals and staff dashboards. Civic Desk collapses both into one static page with two role tabs:

Both roles read and write the same complaints array. Switching tabs is like opening two desktop applications that point at one shared database file — except here the “database” is localStorage under the key kt-civic-desk when you opt in to save.

2. What this is not

Not a production 311 system

Use it to teach or prototype dual-role civic workflows. For a real report, use your municipality’s official channels.

3. Recovered from the desktop pair

The original citizen and staff apps were two desktop windows over one store. This port keeps the dual-role idea in the browser and restores the workflow pieces that do not need a login server or a live 311:

4. Still not in this port

These remain out on purpose — never a working desktop feature, or incompatible with a static no-network demo:

5. Greek category, status, and priority labels

Categories follow a typical Greek municipal taxonomy. The desk UI shows the Greek label with an English subtitle so readers who do not read Greek can still navigate. Status and priority use the same pattern: English keys in the store, Greek-first labels in the UI.

Greek labelEnglish meaning
ΚαθαριότηταCleanliness & waste
ΦωτισμόςStreet lighting
ΔρόμοιRoads & pavements
ΠάρκαParks & green space
ΎδρευσηWater supply
ΆλλοOther
Stored keyGreek labelEnglish
pendingΣε εκκρεμότηταPending
in_progressΣε εξέλιξηIn progress
completedΟλοκληρώθηκεCompleted
rejectedΑπορρίφθηκεRejected
lowΧαμηλήLow
mediumΜεσαίαMedium
highΥψηλήHigh
urgentΕπείγουσαUrgent
privateΙδιωτικόPrivate
publicΔημόσιοPublic

6. Privacy and local-only storage

Nothing you type or attach is uploaded. Photos are read with FileReader into data URLs. With “Save desk data” on, complaint text and metadata go to localStorage (kt-civic-desk) and photo blobs go to IndexedDB (kt-civic-desk-photos) so large images do not blow the typical 5 MB localStorage quota. Clearing the desk or turning off save removes both.

User-rendered complaint text is inserted with textContent — not innerHTML — so descriptions and replies cannot execute script in the page.

Notifications, named templates, and 1–5 ratings are local demo features in the same store. They never leave this device as SMS, email, or a council API.

7. Data shape

{
  "complaints": [
    {
      "id": 1,
      "citizenId": "resident-a",
      "category": "Φωτισμός",
      "location": "Patision Ave & Tositsa",
      "description": "…",
      "photos": ["data:image/jpeg;base64,…"],
      "priority": "high",
      "visibility": "private",
      "lat": 37.9838,
      "lng": 23.7275,
      "department": "lighting",
      "internal_notes": "Coordinate with DEH temporary lighting request.",
      "status": "in_progress",
      "reply": "…",
      "citizen_rating": 4,
      "createdAt": "2026-08-16T10:00:00.000Z",
      "updatedAt": "2026-08-17T14:30:00.000Z"
    }
  ],
  "templates": [],
  "notifications": [],
  "nextId": 2,
  "persist": true,
  "photosInIndexedDB": true
}

JSON export includes full photos arrays for backup. On-device persist strips photo blobs from localStorage and writes them to IndexedDB instead. Import accepts legacy single photo fields (migrated to photos[0]). String ticket ids such as "legacy-1" get a new unused number; they are not dropped. Older exports without triage fields get defaults (priority: "medium", visibility: "private", department: "unassigned", empty internal_notes).

8. How to use

  1. Open Civic Desk and optionally load the sample queue.
  2. As a citizen, pick Resident A or B and submit a complaint (category, priority, visibility, location, optional offline map pin, description, up to three photos ≤ 400 KB each). Save a named template if you want to prefill later — a local demo feature.
  3. Search or filter your list. Edit while the ticket is still pending.
  4. Switch to Staff, filter the queue (status, category, priority, department), assign a department, keep internal notes, update status, and write a reply. Export CSV or print the staff summary.
  5. Switch back to Citizen to see the local notification and, after a reply, a 1–5 rating control. Both are local demo features, not live 311. Assigned department appears as a read-only badge.
  6. Opt in to save on this device (text → localStorage, photos → IndexedDB), export or import JSON, or print.

9. Questions

Is Civic Desk connected to a real municipality?

No. It is an educational in-browser demo. Complaints live in localStorage when you opt in. Nothing is sent to a council backend.

How do citizen and staff views share data?

Both roles read and write the same complaints array under kt-civic-desk. Role tabs are a UX convenience, not separate databases.

Why are categories in Greek?

The desk mirrors common Greek municipality complaint taxonomies. Status and priority use the same pattern: English stored keys with Greek labels and English subtitles.

Does text or photos leave this page?

No. Photos stay on this device (memory + IndexedDB when you opt in). Complaint text uses localStorage. There is no upload endpoint. The map sketch is offline SVG — no tile server.

Why IndexedDB for photos instead of localStorage?

Typical localStorage quotas are about 5 MB per origin. Three JPEG data URLs would burn that quickly. IndexedDB holds the blobs; localStorage keeps text, triage fields, and a photoCount so the desk can warn if blobs are missing.

Can citizens delete any complaint?

Citizens can delete only their own pending complaints. Staff can delete pending or rejected tickets in the shared store.

Are notifications, templates, and ratings live 311 features?

No. In-page notifications, named templates, and 1–5 ratings after a reply are local demo features in this browser. They are not SMS, email, or a council backend.

Is department assign real routing?

No. Department and internal notes are teaching fields on the ticket. They do not call a CRM or notify a real office. Citizens never see internal notes.

Open Civic Desk

Try citizen submission and staff triage in Civic Desk. Local, private, not a production 311 system.