User Roles & Permissions
Five roles, one platform. Every action on SEKEN is gated by a combination of role, KTP status, and account state. This page is the canonical reference for who can do what.
The permission flow
The five roles
Public roles
Buyer
The default role for any signed-up user. No verification required.
Can:
- Browse, search, filter listings
- Like and save items
- Chat with sellers
- Place orders and pay
- Open disputes
- Leave reviews after completed orders
- Submit support tickets
Cannot:
- List items (requires upgrade to seller)
- Access ops, cuan, or admin surfaces
Seller
Any buyer who chooses to list an item becomes a seller. KTP verification is not required to list, but provides significant trust signals.
Can:
- Everything a buyer can
- Create and manage listings
- Generate Biteship shipping labels
- Buy Boost products
- Access seller dashboard and analytics
- Receive disbursements via fin_disbursements
KTP behavior: Verified sellers get a visible badge and higher trust signal in search rankings. Unverified sellers can still operate but with weaker discoverability.
Internal roles
Three staff roles, granted manually by superadmin via ops portal.
Ops admin
Operates ops.pasarseken.id. Day-to-day platform health and customer service.
Can:
- Access all 48 ops modules
- Moderate listings (approve, reject, flag)
- Review KTP submissions
- Resolve disputes
- Manage support tickets
- Suspend or ban accounts
- Run campaigns and broadcasts
- Use ops AI bot for SOP guidance
Cannot:
- Approve disbursements (finance-only)
- View revenue dashboards (read-only summary only)
- Modify role assignments
Finance admin
Operates cuan.pasarseken.id. Handles all financial operations.
Can:
- Approve disbursements with maker-checker workflow
- View revenue dashboards and reports
- Process refunds from escrow
- Sync to Xero (when fully wired)
- Access fin_audit_log
- Read-only view of ops dashboards
Cannot:
- Moderate listings or users (ops-only)
- Resolve disputes directly (ops-only)
- Modify role assignments
Future state: Finance admin role will move to a separate team and dedicated repo to enforce Separation of Duties for fraud prevention. See Cuan Portal.
Superadmin
Founder-level access. Reserved for the founders only.
Can:
- Everything in ops + finance roles
- Assign and revoke staff roles
- Modify platform configuration
- Read complete audit log
- Override any decision
Access surfaces by role
| Surface | Buyer | Seller | Ops | Finance | Superadmin |
|---|---|---|---|---|---|
| pasarseken.id | ✅ | ✅ | ✅ | ✅ | ✅ |
| help.pasarseken.id | ✅ | ✅ | ✅ | ✅ | ✅ |
| ops.pasarseken.id | ❌ | ❌ | ✅ | 🟡 read-only | ✅ |
| cuan.pasarseken.id | ❌ | ❌ | ❌ | ✅ | ✅ |
| docs.pasarseken.id (manager) | ❌ | ❌ | 🟡 | 🟡 | ✅ |
| docs.pasarseken.id (marketing) | ❌ | ❌ | 🟡 | ❌ | ✅ |
docs.pasarseken.id, two-tier access
The internal docs site has two distinct logins:
| Login | Sees |
|---|---|
| Manager | All sections, strategy, finance, operations, playbooks, developer docs, this architecture |
| Marketing | Marketing playbooks, brand guidelines, social media playbook, content strategy only |
This separation lets external marketing freelancers access only what they need without exposure to financial or strategic information.
KTP verification
Indonesian national ID verification via OpenAI OCR + manual ops review.
Status values stored on user_profiles.ktp_status:
| Status | Meaning |
|---|---|
none | Never submitted |
pending | Submitted, awaiting ops review |
approved | Verified, gets badge + trust signal |
rejected | Rejected, can resubmit |
Decision: KTP is a soft trust signal, not a hard gate. Sellers can list without KTP. Verified sellers get badges, better search ranking, and higher buyer trust.
Account states
Stored on user_profiles.account_status:
| Status | Meaning | Enforcement |
|---|---|---|
active | Normal operation | Default state |
suspended | Temporary restriction | UI-gated read-only access |
banned | Permanent block | UI-gated denial |
Decision: Account state enforcement is UI-only, not middleware-level. This is intentional, allows ops staff to investigate suspended accounts, and prevents complete lockout in case of false positives.
Permission enforcement
Three layers of defense:
| Layer | What it checks | File |
|---|---|---|
| 1. Auth | Both headers present: Authorization: Bearer <anon> (well-formed) + X-User-Token SEKEN JWT, verified locally via HS256 (no network round-trip) | backend/src/common/auth/auth.guard.ts |
| 2. Role | User has required role for this endpoint (resolved from JWT claims; superadmin via admin_role_v2) | backend/src/common/auth/ guards + per-controller checks |
| 3. Business | Ownership, account state, KTP, etc. | Each use case |
Where to look in the codebase
| What you want | Where it lives |
|---|---|
| Auth middleware (dual-header guard) | backend/src/common/auth/ (auth.guard.ts, optional-auth.guard.ts) |
| SEKEN JWT sign/verify | backend/src/infrastructure/auth/SekenJwtService.ts |
| KTP verification flow | backend/src/application/user/VerifyKtpUseCase.ts |
| Account state checks | Frontend components + backend use cases |
| Staff role assignment | backend/src/modules/auth/admin-identity.controller.ts |
Next: Customer Journey →