Overview
JMS is a multi-tenant platform where each tenant is an organisation operating one or more academic journals. As a platform admin you sit above all tenants: you provision organisations, enforce quotas, manage billing plans, monitor security events, and control platform-wide behaviour.
| Role | Scope | Capabilities |
|---|---|---|
platform_admin | Entire platform | Full access to all admin pages |
tenant_admin | One tenant | Manages users and settings within their org |
tenant_super_user | One tenant | Elevated tenant-level permissions, no billing access |
editor | Tenant journal | Manages submissions, assigns reviewers |
reviewer | Tenant journal | Reviews assigned manuscripts |
author | Tenant journal | Submits and tracks manuscripts |
/admin section of the UI. Tenant staff never see this area.Getting started
- 1Navigate to
/loginand sign in with your platform admin credentials. - 2You are redirected to
/admin— the Admin Dashboard. - 3The dashboard shows platform-wide stats: active tenants, total users, submissions in the last 30 days, and current queue depth.
/admin/platform-admins) and click Invite Admin. Keep the number of platform admins small — every action is recorded in the audit log.Tenant management
Creating a tenant
- 1Open Tenants (
/admin/tenants) and click New Tenant. - 2Fill in the required fields (see table below).
- 3Click Create. The system provisions the tenant, seeds default journal settings, and sends the owner invite.
| Field | Description |
|---|---|
name | Display name for the organisation |
slug | URL-safe identifier (e.g. oxford-press) — immutable after creation |
plan | Billing plan to attach at creation |
owner_email | Email of the first tenant_admin; receives an invite immediately |
Suspending a tenant
On the Tenant Detail page, click Suspend. Suspended tenants cannot log in and all API calls return 403. Data is retained. To reinstate, click Unsuspend.
User management
- Searching users —
/admin/userssearches across all tenants. Filter by email, name, tenant, or role. - Editing roles — in the User Drawer, use the Roles tab. Role changes apply immediately and are logged.
- Disabling a user — toggle Active off in the User Drawer. The user's JWT is invalidated within 60 seconds.
tenant_admin from the last admin of a tenant leaves it without an administrator. Assign a replacement before removing the current admin.Billing & plans
Plan quotas
Plans are defined at Plans Config (/admin/plans). A value of 0 means unlimited.
| Plan | Submissions | Journals | Members | Storage | AI screenings |
|---|---|---|---|---|---|
| Free | 10 | 1 | 5 | 500 MB | 0 |
| Starter | 100 | 3 | 25 | 5 GB | 50 |
| Professional | 1,000 | 10 | 100 | 50 GB | 500 |
| Enterprise | Unlimited | Unlimited | Unlimited | Unlimited | Unlimited |
BillingService.checkLimit throws a QuotaExceededException. The tenant admin sees a clear error message.Managing subscriptions
Subscriptions (/admin/subscriptions) shows each tenant's current plan, renewal date, and payment status. You can upgrade or downgrade a plan, apply a custom override quota, or cancel a subscription (tenant moves to Free tier at period end).
Security & audit
Audit log
Audit Logs (/admin/audit-logs) records every state-changing action platform-wide.
| Field | Description |
|---|---|
timestamp | UTC time of the event |
actorRef | User or system that performed the action |
action | Verb (e.g. tenant.suspended, user.role_changed) |
resourceType | Entity type (Tenant, User, Submission, …) |
resourceId | Primary key of the affected record |
diff | JSON showing before/after field values |
Suspicious activity
Suspicious Activity (/admin/suspicious-activity) surfaces automated alerts such as repeated failed logins from the same IP, unusual login geography, and bulk-download patterns. Review each alert and dismiss or act (disable user, block IP at nginx layer).
Platform operations
- General Settings (
/admin/general-settings) — default timezone, allowed email domains, session timeout, maximum upload size. - API Keys (
/admin/api-keys) — manage machine-to-machine keys. Always scope to minimum required permissions. Rotate immediately if compromised. - Maintenance Mode (
/admin/maintenance) — all tenant routes return503with a configurable message. Admin routes remain accessible. - Mail queue — JMS uses BullMQ (Redis-backed) for all outbound email. Jobs retry up to 3 times with exponential backoff.
Feature flags & announcements
- Feature Flags (
/admin/feature-flags) — enable or disable features for specific tenants or the entire platform. Takes effect immediately with no deployment required. - Announcements (
/admin/announcements) — broadcasts messages to tenant admins as banners. Set an expiry date so banners auto-dismiss.
Monitoring & health
| Service | What is checked |
|---|---|
| Postgres | Connection pool, query latency |
| Redis | Ping latency, memory usage |
| S3 storage | Bucket reachability, write test |
| Mail queue | BullMQ worker active, queue depth |
Green = within threshold. Yellow = degraded (elevated latency). Red = unreachable.
Troubleshooting
Tenant admin cannot log in
- 1Check Login History for recent attempts — confirm the correct email is being used.
- 2Verify the tenant is not suspended (Tenant Detail page).
- 3Verify the user account is active (User Drawer → Active toggle).
- 4If a JWT issue is suspected, ask the user to clear cookies and retry.
Emails not arriving
- 1Open Health and verify mail queue is green.
- 2Check the BullMQ dead-letter queue for the specific job.
- 3Confirm SMTP credentials in environment config are current.
- 4Check spam folders — SPF/DKIM misconfiguration causes silent delivery failures.
A tenant hit a quota unexpectedly
- 1Open Tenant Detail and compare current usage to plan limits.
- 2Check the audit log for recent bulk imports or unusual activity.
- 3If the quota is legitimately too low, upgrade the plan or apply a one-off override in Subscriptions.
Webhook events not firing
- 1Check the audit log for the relevant action — confirm the event was recorded.
- 2Verify the tenant's webhook URL is reachable from the JMS server.
- 3Check the event delivery log for HTTP error codes from the destination.