Wave 1: permissions roles, account-backed SOP team, critical constraints, password reset, BIM flag
Acts on the site comments from 8/3 plus the follow-ups. Foundation work first — four of the comments all needed the project team to resolve to real user accounts. Permissions vs project role (new) - User.role is now the PERMISSIONS role: admin | project_admin | project_user. project_admin may delete work packages, change a SOP after it is complete, and delete a project; project_user may not (archiving a WP is still open to them). Enforced by require_project_admin() server-side; the UI only hides dead ends. - New User.project_role holds the person's JOB FUNCTION on the project. It grants nothing — it feeds the SOP team pickers and notification routing. - Admin console shows both columns and explains the difference. Migration rewrites the legacy role 'user' to 'project_user'. - Deleting a project was previously open to any member and unaudited; it now needs project_admin and writes an audit event. ProjectData.remove no longer drops the project from the local cache when the server refuses. SOP project team from user accounts - PM/APM/CM/QM and additional team members are pickers over the project's members, storing the account id next to the display name. A name from an older SOP with no matching account is kept and flagged rather than dropped. - The WP Creator lists the SOP team first in the Owner picker, and a new package defaults to whoever is creating it. Critical constraints - SOP constraints carry a Critical flag; buildConstraints() now copies the whole definition through to the package (it previously reduced them to names, losing description too), and critical rows are marked in the WP form. The email on reopen-after-release is wave 3. Password reset by email - login.html gains Forgot password and a set-a-new-password view, offered only when the server reports email is actually configured. - Single-use signed token (AUTH_RESET_MINUTES, default 60) bound to token_version, sent immediately rather than through the notifications outbox so a reset link is never persisted. Identical response for unknown accounts; per-account send cooldown; a completed reset clears any login lockout. - Session and reset tokens are no longer interchangeable. BIM kill-switch - New admin Features card with bim_enabled, OFF by default. The SOP creator hides the BIM section and the Creator treats every package as install-only while it is off; a SOP that already has BIM keeps its data untouched. Verified with two throwaway-database test scripts: 44 checks on the permissions matrix and token handling, 22 on the reset flow end-to-end against a local SMTP sink (real message captured, link extracted and used). Front-end files parse-checked in headless Chrome. Not yet exercised in a browser against a real login. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -62,11 +62,17 @@ AUTH_SECRET_KEY=<strong-random-secret>
|
||||
# unrecoverable: openssl rand -base64 32
|
||||
BACKUP_ENC_PASSPHRASE=<strong-random-passphrase>
|
||||
|
||||
# OPTIONAL — SMTP password for WP-assignment email notifications. Email is OFF
|
||||
# by default and enabled from the Admin console; the host/port/from-address are
|
||||
# configured there, but the password is only ever read from this variable (never
|
||||
# stored in the DB or shown in the UI). Leave unset until you have SMTP details.
|
||||
# OPTIONAL — SMTP password for WP-assignment email + password-reset links. Email
|
||||
# is OFF by default and enabled from the Admin console; the host/port/from-address
|
||||
# are configured there, but the password is only ever read from this variable
|
||||
# (never stored in the DB or shown in the UI). Leave unset until you have SMTP
|
||||
# details.
|
||||
# SMTP_PASSWORD=<smtp-app-password>
|
||||
|
||||
# OPTIONAL — password-reset link lifetime (minutes) and the per-account send
|
||||
# cooldown (seconds). Defaults shown; both only matter once email is enabled.
|
||||
# AUTH_RESET_MINUTES=60
|
||||
# AUTH_RESET_COOLDOWN_SECONDS=120
|
||||
```
|
||||
|
||||
The API builds its own DB connection string from the `POSTGRES_*`
|
||||
@@ -295,6 +301,51 @@ TLS / From address and flips the master toggle.
|
||||
package contents — so customer IP stays behind the login.
|
||||
- Use the card's **Send test email** button to confirm SMTP before enabling.
|
||||
|
||||
### Self-service password reset
|
||||
|
||||
Turning email on also enables **Forgot password** on the login page. Until then the
|
||||
link explains that an admin must reset it (`server/manage_users.py`, or the Admin
|
||||
console's **Reset password** button).
|
||||
|
||||
- The emailed link carries a short-lived signed token — `AUTH_RESET_MINUTES`
|
||||
(default 60). It is **single-use**: completing a reset bumps the account's
|
||||
`token_version`, which both burns the link and signs out that user's other
|
||||
sessions. A completed reset also clears any login lockout.
|
||||
- `/api/auth/forgot-password` answers **identically for unknown accounts**, so it
|
||||
can't be used to discover usernames. Misses are recorded in the audit log
|
||||
(`password_reset_miss`) instead.
|
||||
- One reset mail per account+client per `AUTH_RESET_COOLDOWN_SECONDS` (default 120)
|
||||
so the form can't be used to flood someone's inbox. The throttle is per worker
|
||||
and in-memory; the token expiry is the real control.
|
||||
- Reset mails are sent **immediately, not through the notifications outbox** — a
|
||||
reset link must never be persisted where an admin could read it and take over an
|
||||
account.
|
||||
- Set `app_base_url` in the admin card, or the emailed link will be relative and
|
||||
therefore useless.
|
||||
|
||||
## Permissions roles
|
||||
|
||||
`User.role` is the **permissions** role; `User.project_role` is the person's **job
|
||||
function** on the project (Project Manager, Superintendent, …) and grants nothing.
|
||||
Both are set in the Admin console's user table.
|
||||
|
||||
| Role | May do |
|
||||
|---|---|
|
||||
| `admin` | User administration, app settings, and every project |
|
||||
| `project_admin` | On assigned projects: delete work packages, change a **completed** SOP, delete the project |
|
||||
| `project_user` | Create/edit work packages, author a SOP up to completion; may archive a WP but not delete one |
|
||||
|
||||
Enforced server-side by `require_project_admin` in `server/app.py`; the front end
|
||||
only hides controls to avoid dead-end clicks. Accounts created before this change
|
||||
carried the role `user`, which the migration rewrites to `project_user`.
|
||||
|
||||
## Feature flags
|
||||
|
||||
**Admin console → Features.** `bim_enabled` is **OFF by default**: the SOP creator
|
||||
hides the BIM/VDC section and every project is install-only (IWP). A SOP that
|
||||
already has BIM enabled keeps its data — it just stops being offered — so turning
|
||||
the flag off never deletes BIM types, gates, or sequence steps.
|
||||
|
||||
## Schema migrations (Alembic)
|
||||
|
||||
Schema is managed by **Alembic** (`server/alembic/`). The API container runs
|
||||
|
||||
Reference in New Issue
Block a user