# Settings

All routes use /api/v1/settings, current-account authentication, trusted browser origins and private no-store responses. Errors use the existing envelope and Indonesian catalog. STATE_CONFLICT details include EMAIL_EXISTS, SELF_ADMIN_CHANGE or LAST_ADMIN; invalid old password is VALIDATION_ERROR with CURRENT_PASSWORD_INVALID. Password operations are rate limited.

PATCH /profile atomically saves name, normalized email, nullable position and an optional complete password group. GET /auth/me supplies the profile. New passwords are 8-128 characters; old-password verification and hash compare protect concurrent updates. Audits contain public fields and passwordChanged only, never credentials or hashes.

ADMIN-only GET /users accepts q, role, status=all|active|inactive, page and pageSize (max100). POST /users requires a manually entered initial password, name, email and role; an ADMIN communicates that password outside this application. PATCH /users/:id edits public fields, role and isActive, never password. There is no reset-password, email invitation or hard-delete endpoint. Self-deactivation/role changes are rejected. Singleton database locking serializes admin mutations with a current-role check; at least one active ADMIN remains.

GET/PATCH /system expose only plantName (trimmed 1-150 characters). Missing-row reads return Pilot Plant Utama without writing. Writes initialize id=1 using schema defaults and preserve timezone/currency/autoApprovalRule. Current plantName is included in report metadata and Excel/print output even for historical periods; other report semantics are unchanged.

No migration, notification preference changes, email, calibration or approval-policy changes. Settings removes obsolete notification and priority-auto-approval controls. Account deactivation denies subsequent authenticated requests; reactivation allows still-valid JWTs again. Password changes do not revoke existing JWTs. No new session/revocation model is implied.

Verification: run `node --env-file=.env prisma/verify-settings.cjs` from apps/api for guarded disposable MySQL validation, or add `--browser` for the compiled UI in headless Chrome. These commands create and remove dedicated test databases; they do not migrate or seed the application database. See the change verification.md for recorded results.
