Files
OmniOilPersonal/openspec/changes/notify-approved-access-requests/prd.md

5.4 KiB

PRD: Provision Approved Access Requests

Problem

When OmniOil/Kyrbot approves a public access request, the system currently only changes an internal review status. It does not create the customer admin account, does not bind access to an operational scope, and does not notify the requester with an activation path. This leaves onboarding dependent on manual backoffice steps and makes it easy for approved customers to get stuck.

Goal

Approving an access request from Console should complete the first operational onboarding step: create the customer admin account, connect it to the approved operational scope, generate a secure activation link, and email the customer without exposing passwords.

Users

  • Platform operator: reviews requests and approves/rejects them from Console.
  • Platform admin: has the same flow plus future ability to resolve provisioning conflicts.
  • Customer admin: the business contact who requested access and will activate the first customer-side admin account.

User Stories

  • As a platform operator, I want approval to provision the customer's initial admin access so I do not manually create users after every approval.
  • As a platform operator, I want to see whether the activation email was sent or failed so I know whether follow-up is needed.
  • As a platform operator, I want to resend a failed or expired activation invitation without approving the request again.
  • As a customer admin, I want to receive a secure activation email so I can set my own password and enter OmniOil.
  • As OmniOil/Kyrbot, we want an audit trail for every approval, provisioning action, activation email, resend, and activation.

Functional Requirements

  1. Approval shall only apply to requests in pending or in_review.
  2. Approval shall create or link the customer operational scope before emailing the customer.
  3. Approval shall create the initial customer admin user with role admin.
  4. Approval shall not create platform_admin or platform_operator users for customers.
  5. The created customer admin shall remain unable to log in until activation is completed.
  6. The system shall generate a single-use activation token with expiration.
  7. The system shall store only a token hash, never the raw token.
  8. The email shall include an activation link, expiration notice, company name, and support contact.
  9. The email shall not include a password.
  10. If SMTP fails, approval/provisioning shall remain durable and Console shall show the failure.
  11. Console shall allow resending/rotating the activation invitation for approved provisioned requests.
  12. Activation shall let the customer admin set a password and then mark the user active.
  13. The system shall audit approval, provisioning, email sent, email failed, resend, and activation.
  14. Approval shall create an initial 7-day project trial using the existing project subscription model.
  15. Activation-token expiry and project-trial expiry shall remain separate concepts.

Non-Functional Requirements

  • Security: activation tokens must be high entropy, expiring, single-use, and hash-only at rest.
  • Reliability: SMTP failure must not corrupt approval/provisioning state.
  • Auditability: all state transitions must be visible in audit logs.
  • Minimality: reuse existing users, roles, edge_projects, and user_project_access unless design proves a dedicated tenant table is required now.
  • Billing boundary: use existing subscriptions.status = 'trial' and trial_ends_at for the initial trial, but do not implement full payment enforcement in this change.
  • Operability: deployment docs must explain SMTP and activation URL env vars.

Open Questions

  1. Resolved: approval creates a new edge_projects row automatically from the access request data.
  2. Resolved: activation uses app.omnioil.app/activate because it belongs to the customer Admin app, not the provider Console or public landing.
  3. Resolved: if users.email already exists, approval links the existing user to the newly created project instead of creating a duplicate user.
  4. Resolved: activation links expire after 7 days.
  5. Resolved: resending invalidates all previous unconsumed activation tokens and creates a fresh token.

Product Decisions

  • Auto-provisioning: approval automatically creates the first edge_projects record using request-derived data.
  • Activation URL: INVITATION_BASE_URL=https://app.omnioil.app, route /activate.
  • Existing user behavior: link existing user by email to the new project; do not duplicate accounts.
  • Expiration: activation tokens expire after 7 days.
  • Resend behavior: rotate token and invalidate previous unconsumed invitations.
  • Trial: provisioned projects start with a 7-day trial subscription.
  • Billing enforcement: suspending projects after non-payment/trial expiry is a later billing lifecycle change, not part of activation-token validation.

Success Metrics

  • An approved request results in a provisioned customer admin without manual DB/user creation.
  • Operators can tell from Console whether the activation email was sent.
  • Customers can activate without receiving or sharing passwords.
  • Failed SMTP delivery can be recovered through resend.
  • No raw activation token appears in database, logs, or API responses after email construction.

Out of Scope

  • Full tenant/account hierarchy redesign.
  • Bulk user import.
  • Creating production assets/devices/variables.
  • Billing automation.
  • Marketing email automation.