Files
nick-doc/00 - Overview/Roles & Personas.md
Siavash Sameni dceaf82934 audit: 2026-05-30 full-codebase audit — report, issues, docs, runbooks
Full-codebase-audit 2026-05-30 outputs:
- Audit report: 09 - Audits/Full Codebase Audit - 2026-05-30.md
- 81 issue files ISSUE-055..135 (decisions + 1 skipped no-brainer).
- Scanner docs from scratch (was zero): architecture, data model, API ref, payment
  flow, operations runbook + repo README.
- Doc-sync updates across API reference, data models, flows, design system.
- Secret Rotation Runbook (08 - Operations) for the exposed credentials.
- Reusable workflow guide (07 - Development) + .claude/workflows/full-codebase-audit.js.

Issues remain status:open intentionally — the code fixes are uncommitted-then-committed
working-tree changes per repo and aren't "resolved" until merged/deployed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 18:48:04 +04:00

14 KiB

title, tags, created
title tags created
Roles & Personas
overview
roles
personas
permissions
rbac
2026-05-23

Roles & Personas

[!info] Where roles live in code The hard role enum is defined in backend/src/models/User.ts:94 as "admin" | "buyer" | "seller" | "resolver". The resolver role was added to the backend in commit fce8a19 and is now a first-class enum value in User.ts, UserRole enum in shared/types/index.ts, and the dispute routes. Support is implemented as an admin variant (a dedicated support@amn.gg user is created at bootstrap — see backend/TODO.md) rather than as its own enum value. Permission checks live in route middleware and in service guards.

Amn has five user personas. Four are first-class roles in the data model; the fifth (Support) is a special-cased admin with reduced privileges.

flowchart LR
    Visitor["Anonymous visitor<br/>(blog, public shops)"]
    Buyer["Buyer<br/>(User)"]
    Seller["Seller<br/>(Owner)"]
    Support["Support<br/>(admin variant)"]
    Admin["Admin"]
    Resolver["Resolver<br/>(dispute specialist)"]

    Visitor -->|signs up| Buyer
    Buyer -->|requests seller mode<br/>+ admin approval| Seller
    Buyer & Seller -->|opens ticket| Support
    Support -->|escalates| Admin
    Admin -->|assigns role| Resolver

Buyer (User)

[!example] Who they are Default new user. Anyone who signs up is a buyer until they request seller status. The persona name in the UI is "User" but the model role is buyer.

Primary workflows

  • Browse and search the public marketplace and request templates.
  • Create a Purchase Request describing what they want — product type (physical / digital / service / consultation), budget, urgency, delivery info, attachments. See backend/src/models/PurchaseRequest.ts.
  • Review incoming Seller Offers, negotiate over chat, accept the best one.
  • Pay via the Request Network in-house checkout, using a supported EVM wallet through Wagmi/WalletConnect and the platform's payment request metadata.
  • Track the order through processing → delivery → delivered → confirming → completed states.
  • Confirm receipt (or let the SLA auto-confirm), leave a review, accrue points.
  • Open a Dispute if delivery never lands, item is wrong, or quality is poor.
  • Refer friends via their personal referral code; earn points per signup that converts.
  • Manage profile: avatar, addresses, wallet address, passkeys, notification preferences, language.

Key permissions

  • Create, edit, cancel own purchase requests.
  • Accept / reject offers on own requests.
  • Initiate payments on own requests.
  • Open disputes on own orders.
  • Chat with sellers on own open requests and disputes.
  • Read public sellers, public requests, public blog.
  • Cannot: see other users' private data, moderate content, issue payouts, change another user's role.

Dashboard sections (frontend routes)

The buyer dashboard lives under /dashboard (frontend/src/app/dashboard/). Notable areas:

  • /dashboard — overview (recent requests, recent offers received, points balance)
  • /dashboard/request — list, detail, and create flow for purchase requests
  • /dashboard/request-template — saved templates and the catalogue of admin templates
  • /dashboard/chat — all conversations
  • /dashboard/payment — payment history (in + out) and active invoices
  • /dashboard/disputes — open and resolved disputes
  • /dashboard/points — points, levels, referrals
  • /dashboard/account — profile, security (passkeys), addresses, language
  • /dashboard/post — read-only blog reader (also public)

[!tip] See also Full buyer playbook in User Guide. Auth specifics in Authentication Flow.


Seller (Owner)

[!example] Who they are A buyer who has been promoted to role: "seller". The UI sometimes calls them "Owner" because they own a shop. Sellers retain all buyer capabilities — they can still post requests of their own.

Primary workflows

  • Configure shop: shop name, banner, description, response time SLA, accepted payment methods, payout wallet address. See backend/src/models/ShopSettings.ts and frontend/src/sections/shop-settings/.
  • Discover requests through the seller feed (filtered by category and preferred-seller status). Receive live notifications when a relevant request is posted via the sellers / seller-<id> Socket.IO rooms (backend/src/app.ts:101-112).
  • Submit offers with price in USDT (the only supported currency for the escrow MVP — USD/EUR/IRR removed in commit 3aaa2fe), delivery time, optional attachments and notes.
  • Negotiate in the per-request chat — bilateral with the buyer until an offer is accepted.
  • Fulfil the order: ship physical goods (with optional tracking number), or upload/email digital deliverables.
  • Use the delivery code for physical handoffs: a six-digit one-time code the buyer reads to the courier to confirm receipt.
  • Receive payout to the configured wallet after ledger-gated release. Today this is an admin/custody-signer operation; the target path is Safe/hardware-backed approvals as described in PRD - Decentralized Custody and Smart-Contract Escrow Roadmap.
  • Manage Request Templates scoped to their shop — publish "off-the-shelf" offerings buyers can purchase in one click.
  • Engage with reviews and disputes: respond to reviews, contest disputes, provide evidence.

Key permissions

  • All buyer permissions.
  • Create / edit / withdraw own seller offers.
  • Read all public purchase requests + read-only access to requests where they have an active offer.
  • Manage own shop settings, payout wallet, business hours.
  • Publish Request Templates scoped to their shop.
  • Mark orders as shipped, upload digital deliverables, request delivery codes.
  • Respond in disputes they are a party to.
  • Cannot: see another seller's analytics, edit another seller's shop, moderate the platform.

Dashboard sections

Seller dashboard reuses the same /dashboard shell with extra modules:

  • /dashboard/shops — public-facing shop browser (also visible to buyers)
  • /dashboard/shop-settings — edit own shop, payout wallet, working hours
  • /dashboard/request-template — create / edit shop-scoped templates
  • /dashboard/payment — receivables, payout history, pending releases
  • /dashboard/disputes — disputes where the seller is the respondent
  • /dashboard/seller/marketplace/offersOffer Management (tabbed view of all own offers filtered by status: pending / accepted / rejected / withdrawn; inline withdraw action; commit 9cf1686)

[!tip] See also Seller Guide walks through onboarding, first listing, and payout setup end-to-end. Payments Overview explains the escrow + payout state machine.


Admin

[!example] Who they are Platform operators with full read/write access. Admins are seeded at startup via backend/src/infrastructure/database/init-admin.ts. There is typically one root admin (admin@amn.gg) and additional admins promoted through database operations or a dedicated admin-creation endpoint.

Primary workflows

  • Moderate users: suspend / unsuspend accounts (User.status: "active" | "suspended" | "deleted", see backend/src/models/User.ts), promote buyers to sellers, ban repeat offenders.
  • Moderate marketplace content: categories (Category model), request templates (the canonical platform-wide ones), blog posts.
  • Resolve disputes: get assigned to disputes, drive them to resolution, choose an outcome (refund | replacement | compensation | warning_seller | ban_seller | no_action). See backend/src/services/dispute/DisputeService.ts and Dispute Flow.
  • Operate payments: trigger ledger-gated releases/refunds, review Request Network webhooks, inspect derived destination wallets, fetch on-chain transactions, and manually confirm stuck payments only after Transaction Safety Provider checks.
  • Configure the platform: levels (LevelConfig), points multipliers, blog seed content, default templates.
  • Run data cleanup: /api/admin/cleanup exposes destructive maintenance utilities (services/admin/).
  • Author blog posts via the TipTap rich-text editor.
  • Monitor health: Request Network webhook/reconciliation status, ledger enforcement, custody signer/Safe readiness, Redis, and MongoDB.

Key permissions

  • All read and write across the platform — no row-level scoping.
  • Promote users, change roles, suspend accounts.
  • Approve / reject seller applications.
  • Resolve any dispute, override any payment state.
  • Trigger payouts and refunds.
  • Edit / delete any blog post, template, or category.
  • Run admin cleanup endpoints (irreversible — use with care).
  • Access the full Sentry stream and webhook logs.

Dashboard sections

Admins see the buyer/seller surfaces plus dedicated admin modules (typically under /dashboard with admin-only guards, growing into a dedicated /admin area in later versions):

  • User management (search, suspend, role change)
  • Dispute queue with assignment and resolution
  • Payment console (manual confirmation, release/refund dispatch, Request Network webhook and ledger log)
  • Category and template management
  • Blog editor (publish / unpublish / featured)
  • Platform analytics (TODO — see backend/TODO.md)
  • Data cleanup utilities

[!warning] Destructive operations /api/admin/cleanup/* and direct role mutations are not undoable. Admin actions should be logged to an audit trail. Audit logging is on the roadmap (backend/TODO.md → Security Enhancements → Audit Logging).

[!tip] See also Admin Guide gives the step-by-step for moderation, dispute resolution, and payment operations.


Support

[!example] Who they are A dedicated support persona — the seeded support@amn.gg account — that exists to handle user tickets and triage disputes without granting full destructive access. Implemented as an admin role with a restricted permission profile applied in middleware (see backend/TODO.md → "Support user creation").

Primary workflows

  • Join existing chats to assist a buyer or seller in real time.
  • Triage disputes: read incoming disputes, attach notes, assign to the right admin, set priority.
  • Answer user queries about payments and orders without performing the payment action itself.
  • Escalate anything that requires destructive action (refunds, bans, manual payouts) to a full admin.

Key permissions

  • Read access to all user accounts (no PII edits).
  • Read access to all disputes and chats.
  • Comment / reply in disputes and chats (write access scoped to messages, not resolution).
  • Cannot: change roles, issue payouts, suspend users, delete content, resolve a dispute, edit settings.

Dashboard sections

Support sees a stripped-down admin view focused on the inbox:

  • Support chat queue
  • Dispute triage list
  • User lookup (read-only)
  • Order lookup (read-only)

Resolver

[!example] Who they are A platform-employed dispute resolver (role: "resolver"). Added to the backend as a first-class role in commit fce8a19. Resolvers have targeted authority to mediate and formally resolve disputes — they can assign disputes, update status, issue final resolutions (including ban_seller or refund), view statistics, and bypass chat membership checks (commit 766a9a2) to read/send in any chat.

Primary workflows

  • Review dispute details: read buyer and seller evidence, chat history, delivery confirmations.
  • Communicate directly through any chat — bypasses participant membership guard.
  • Assign, update status, and resolve disputes with the same actions as admins (refund | replacement | compensation | warning_seller | ban_seller | no_action).
  • Monitor dispute health via GET /api/disputes/statistics.

Key permissions

  • Full triage on disputes: POST /:id/assign, PATCH /:id/status, POST /:id/resolve, GET /statistics.
  • Read and write messages in any chat (bypass membership check in ChatService).
  • Read any dispute and its evidence.
  • Cannot: change roles, issue payouts, suspend users, delete content, access non-dispute admin endpoints.

[!note] Implementation The resolver role was added as a first-class backend enum in commit fce8a19 (User.ts, UserRole in shared/types/index.ts, dispute routes). Chat bypass was added in commit 766a9a2.


Cross-cutting concerns

Role transitions

From To How Audit
Anonymous Buyer Self-service signup User created
Buyer Seller Application → admin approval User.role change
Buyer / Seller Admin Manual DB / boot-time seed High-risk, manual
Buyer / Seller Resolver Admin role assignment User.role change
Admin Support Permission profile applied at middleware Role stays admin

Permission model

Permissions are enforced at three layers:

  1. Route middleware (e.g. requireAuth, requireRole('admin')) — coarse gating on the HTTP layer.
  2. Service guards — finer ownership checks (e.g. "you can only edit a request whose buyerId matches your userId").
  3. Frontend route guardsfrontend/src/auth/guard/ hides UI from users who would be rejected anyway, preventing dead-ends.

Identity sources

  • Email + password — primary, with bcrypt hashing.
  • Passkey (WebAuthn) — multi-device, stored in User.passkeys[].
  • Google OAuth — server-verified, links by email.

See Authentication Flow for the full sequence diagram.

Internationalisation per persona

All four personas see the same six-language UI (en, fr, vi, cn, ar, fa) with the default fallback being Persian (fa) — see frontend/src/locales/locales-config.ts:39. Date formatting switches to the Jalali calendar in Persian.


See also