|
| 1 | +--- |
| 2 | +"@objectstack/plugin-auth": minor |
| 3 | +"@objectstack/platform-objects": minor |
| 4 | +"@objectstack/rest": minor |
| 5 | +"@objectstack/spec": minor |
| 6 | +--- |
| 7 | + |
| 8 | +feat(auth): admin direct user management, phone sign-in, and identity bulk import (#2766, re-scoped #2758) |
| 9 | + |
| 10 | +`sys_user` is managed by better-auth and its generic CRUD is suppressed, so |
| 11 | +until now the only way to add a teammate was the email-dependent invite flow. |
| 12 | +This ships three staged capabilities: |
| 13 | + |
| 14 | +- **Admin direct user management** — `POST /api/v1/auth/admin/create-user` |
| 15 | + and a wrapped `POST /api/v1/auth/admin/set-user-password` (ADR-0068 |
| 16 | + platform-admin gate; better-auth pipeline so credentials are real). Optional |
| 17 | + generated temporary password (returned once, never persisted or logged) and |
| 18 | + a new `sys_user.must_change_password` flag enforced through the ADR-0069 |
| 19 | + authGate (`403 PASSWORD_EXPIRED` until the user changes it). New |
| 20 | + `create_user` action and upgraded `set_user_password` action on the Users |
| 21 | + list — pure schema, no frontend changes. |
| 22 | +- **Phone sign-in (opt-in `auth.plugins.phoneNumber`)** — better-auth |
| 23 | + phoneNumber plugin, phone+password only (`POST /sign-in/phone-number`); |
| 24 | + OTP flows stay off until SMS infrastructure exists. Adds |
| 25 | + `sys_user.phone_number` (unique) / `phone_number_verified`. Phone-only |
| 26 | + accounts get an undeliverable placeholder email |
| 27 | + (`u-<random>@placeholder.invalid`, never derived from the phone number); |
| 28 | + all auth mail callbacks refuse placeholder recipients. |
| 29 | +- **Identity bulk import** — `POST /api/v1/auth/admin/import-users` accepts |
| 30 | + the same payloads as the generic import routes (rows/csv/xlsx, dryRun, |
| 31 | + upsert by email or phone) but writes every row through better-auth. |
| 32 | + Password policies: `invite` (reset-link email per created user; requires an |
| 33 | + EmailService) and `temporary` (per-row one-time passwords + forced change). |
| 34 | + Sync only, ≤500 rows per request; no undo; upsert updates touch profile |
| 35 | + fields only and can never reset an existing user's password. |
| 36 | + `prepareImportRequest` and the CSV/xlsx parsers moved from rest-server.ts |
| 37 | + to an exported `import-prepare.ts` module (behavior unchanged). |
0 commit comments