Skip to content

Identity Module

Purpose

Manages the security and access foundation of the platform: tenant provisioning, user management, role-based access control, and authentication. Every other module enforces permissions defined here. Multi-tenancy isolation (each tenant's data is completely separate via PostgreSQL RLS) is the responsibility of this module and the database layer it configures.

Actors

Actor Interaction
Admin Full access: manage users, roles, tenant settings, subscription
Manager (Kierownik) View own profile; no user management
Technologist (Technolog) View own profile only
Worker (Pracownik) View own profile only
Warehouse Keeper (Magazynier) View own profile only
Sales Rep (Handlowiec) View own profile only
QA Specialist View own profile only
Accountant (Księgowa) View own profile only

Use Cases

IDN-UC-01: Tenant Registration and Onboarding

Actor: New user (self-service) Phase: 1

New company registers: username (required, unique per tenant), email (optional), password (min 12 chars for Admin/Manager roles), company name. On registration:
- New tenant record created with unique tenant_id
- Admin account created for the registering user
- 30-day free trial started automatically (subscription_status: trial)
- PostgreSQL RLS context set to tenant_id for all subsequent requests

User identity fields:
- username (required, unique per tenant) — the primary login identifier
- email (optional) — for notifications and optional login method
- birth_date (optional) — used for mobile/tablet login by Worker role
- pin_code (hashed, 6 digits) — for PIN-based login

Role-based authentication: - Admin/Manager: username + password (min 12 chars), OR username + PIN - Worker/Technologist/Warehouse Keeper/Sales Rep/QA Specialist/Accountant: username + PIN, OR birth_date + PIN (mobile/tablet)

Worker account creation (email-less): - Admin creates account with username only (no email required) - Admin sets temporary password - On first login, worker is forced to set their 6-digit PIN - PIN becomes their ongoing credential

Onboarding wizard (5 steps, each skippable):

The wizard is a frontend-only guided mode — it restricts navigation to a specific sequence of screens but each step delegates to the owning module's standard API (Identity for users, ItemCatalog for items, Warehouse for warehouses, Manufacturing for recipes). No special backend endpoints or module boundary bypasses.

  1. Company data: name, address, NIP, logo upload
  2. Create first warehouses (system pre-creates defaults: "Raw Materials" and "Finished Goods")
  3. Add first users (optional)
  4. Import raw materials from Excel or add 3 manually
  5. Create first recipe (guided)

Goal: registration to first production order in < 30 minutes.

Business rules: 1. One Admin account is always guaranteed per tenant — Admin cannot be demoted below Admin if they are the last Admin user 2. Email, when provided, must be unique across all tenants. Null/blank email is always permitted and never compared for uniqueness. Email is required for the Admin role — an Admin account cannot be saved without a valid email address. For all other roles, email is optional. 3. Trial period: 30 days with Business tier feature access. Days 28–30: Admin receives a daily email warning and sees a persistent dashboard banner. Day 31: subscription transitions to suspended and all logins are blocked. Full data is preserved during suspension (not deleted). 4. Explicit cancellation: login is blocked immediately on cancellation. No grace period. Data is preserved for 5 years (see IDN-UC-06).


IDN-UC-02: User Authentication

Actor: All roles Phase: 1

Login is handled via the AuthProvider abstraction. Phase 1 implements LocalPasswordProvider (email + bcrypt-hashed password lookup). The abstraction is designed so that additional providers (e.g. OAuth via OIDC) can be added in Phase 2 without changes to the authentication flow or JWT issuance logic.

AuthProvider contract (conceptual): - Input: credentials (varies by provider type) - Output: UserIdentity (user_id, tenant_id, email, roles) - The AuthProvider is the only component that ever touches credential material - JWT issuance happens after any provider successfully returns a UserIdentity

Phase 1 — LocalPasswordProvider: Login via username or email + password (system looks up account by both fields; username is the primary identifier). System returns a JWT (short-lived, 15 minutes) and a refresh token (7 days). Refresh token rotation on use.

Business rules: 1. Password must be minimum 12 characters (for Admin/Manager roles) 2. PIN must be exactly 6 numeric digits (for Worker and other roles) 3. Passwords/PINs are bcrypt-hashed — never stored in plain text and never logged 4. JWT contains: user_id, tenant_id, roles (list) — all other lookups use these 5. After 5 consecutive failed login attempts: account temporarily locked for 15 minutes; email notification to account owner (if email exists). For Worker accounts without email, Admin receives an email notification + an in-app dashboard alert listing all locked accounts; the lock self-resolves after 15 minutes without Admin intervention. 6. Lockout counter resets to 0 on successful login 7. Session invalidated on password change, PIN change, or explicit logout 8. Provider-specific credential material (password hashes, PIN hashes) never leaves the AuthProvider layer


IDN-UC-03: Manage Users

Actor: Admin Phase: 1

Admin can: invite users (email, name, one or more roles), reset passwords, deactivate users, and change role assignments.

User creation flows:

Users with email (Admin, Manager, Accountant, Sales Rep, etc.): 1. Admin creates account with username + (optional email) + assigned roles 2. If email provided: system sends invitation link (valid 48 hours, single-use) 3. User clicks link, sets their own password (per role requirements) 4. Account becomes active after setup completion

Workers without email (Pracownik, Magazynier roles): 1. Admin creates account with username + birth_date + assigned roles 2. Admin manually enters a temporary PIN (Admin authors and knows it). System saves it hashed and does not display it back after saving. Admin communicates the temporary PIN to the Worker through offline means (e.g., in person, phone call). This is distinct from permanent passwords and PINs, which Admins never see or author. 3. First login: Worker uses username + temp PIN 4. System forces immediate PIN change 5. Worker sets their own 6-digit PIN

Invitation flow (email users): Invitation link is time-limited (48 hours, single-use). User completes setup by setting password. Admin never sees user's actual password/PIN.

Effective permissions: Each user can hold multiple roles. Permissions = union of all assigned roles. Admin sees permission preview before confirming role assignment.

Business rules: 1. A user cannot be deleted — only deactivated (preserves audit trail attribution) 2. Deactivated users cannot log in; historical actions remain attributed 3. Admin cannot remove Admin role from themselves if last Admin 4. Role changes take effect on next login 5. Invitation links expire after 48 hours (single-use) 6. If invitation link expires or is not used, Admin can resend (generates new link, invalidates old)


IDN-UC-04: Role Definitions

Actor: Admin Phase: 1

Eight predefined roles are available for assignment. No custom roles in Phase 1.

Each role is a named identity within the system. The access each role has within individual modules (Manufacturing, Warehouse, CRM, etc.) is defined by those modules — not here.

Role Polish Name Identity-level capabilities
Admin Administrator Full access to user management, roles, tenant settings, subscription, and audit log
Manager Kierownik View own profile; no user management
Technologist Technolog View own profile only. Has full cost breakdown visibility in Manufacturing (guide_price and cost calculations) — same as Manager, read-only.
Worker Pracownik View own profile only
Warehouse Keeper Magazynier View own profile only
Sales Rep Handlowiec View own profile only
QA Specialist Specjalista QA View own profile only
Accountant Księgowa View own profile only

Business rules: 1. The eight role names and Polish labels are system constants — they cannot be renamed or deleted by tenant Admins 2. Admin can view a per-role description summary when assigning roles to help avoid accidental over-permissioning 3. When multiple roles are assigned to a user, effective permissions across all modules = union of the permissions of all assigned roles


IDN-UC-05: Role Assignment and Changes

Actor: Admin Phase: 1

Admin assigns one or more roles to each user at invitation time. Role assignments can be changed later — changes take effect on the user's next login (existing JWT remains valid until expiry, max 15 minutes).

When assigning roles, Admin sees a combined permission preview (union of all selected roles' capabilities) before confirming. This prevents accidental over-permissioning.

Business rules: 1. A user must have at least one role at all times 2. A user may hold multiple predefined roles simultaneously; effective permissions = union of all assigned roles 3. Role changes take effect on next login — the current session JWT retains the previous roles until expiry (max 15 minutes) 4. Admin cannot remove the Admin role from themselves if they are the last Admin in the tenant 5. When a user's roles are changed, an audit log entry is created: who changed it, from which role set, to which role set, when


IDN-UC-06: Subscription Lifecycle Management

Actor: Admin Phase: 1

Subscription states: trialactivesuspendedcancelled

  • Trial: 30 days; Business tier feature set; no payment required. Warning period: days 28–30, Admin receives daily email + persistent dashboard banner urging subscription. Day 31: transitions to suspended.
  • Active: valid subscription; tier determines user seat limit and feature access
  • Suspended: payment failed or trial expired without subscription; login blocked for all users; data preserved for 5 years (regulatory requirement). Admin receives a 3-day advance email warning before suspension triggers (admin email is guaranteed — see IDN-UC-01 BR-2).
  • Cancelled: explicit cancellation; login blocked immediately (no grace period); data preserved for 5 years (regulatory requirement — no automatic deletion)

Pricing tiers (configured externally, referenced here for access control): - Starter: up to 3 users - Pro: up to 10 users - Business: up to 25 users - Enterprise: unlimited

Payment handling: Subscription payments are handled externally (primarily bank transfer). GrinSystem does not have a payment UI — the Identity module only tracks the resulting subscription state transitions.

Business rules: 1. Suspension blocks all user logins including Admin — Admin receives email with payment link 3 days before suspension triggers. Admin email is required (BR-IDN-02), so this warning is always deliverable. 2. All tenant data is preserved for 5 years regardless of subscription status (Polish food safety regulatory requirement). No automatic deletion on suspension or cancellation — only login blocking. 3. User seat limit is enforced at user creation — Admin cannot create a user that would exceed the tier limit. 4. Trial = Business tier feature set. User seat limit during trial = Business tier limit (up to 25 users).


IDN-UC-07: Audit Log

Actor: System (auto); viewed by Admin Phase: 1

Every write operation (create, update, delete/deactivate) is recorded in an immutable audit log entry containing: user_id, tenant_id, action, entity_type, entity_id, old_value (JSON), new_value (JSON), timestamp.

Admin can view the audit log via the UI. The log cannot be edited or deleted. Export functionality is out of scope for Phase 1 — it will be specced separately when regulatory requirements for machine-readable export are confirmed.

Business rules: 1. Audit log is immutable — no modification or deletion is allowed at any layer 2. Sensitive fields (password hashes, JWT secrets, OAuth tokens) and PII fields (IP addresses) are never logged 3. Audit log retention: minimum 5 years (Polish food safety regulatory requirement)


IDN-UC-08: Forgot Password / Reset PIN

Actor: Any user (unauthenticated) Phase: 1

Users with email can initiate self-service password/PIN reset. Workers without email (PIN-only accounts) must contact Admin for PIN reset.

Password reset flow (email users): 1. User submits username or email on the "Forgot password" screen 2. System always responds with "If this account exists, you will receive a reset link" — no enumeration 3. If email exists on account: system sends reset link (valid 1 hour, single-use) 4. User clicks link and sets a new password/PIN 5. All existing sessions for that user are immediately invalidated

PIN reset flow (email-less workers): 1. Worker contacts Admin (offline process — phone, in-person) 2. Admin verifies identity 3. Admin generates temporary PIN in system 4. Worker logs in with temp PIN and is forced to set new PIN

Business rules: 1. Reset link is single-use — clicking it a second time shows an error 2. Reset link expires after 1 hour 3. New password must meet role requirements (12 chars for Admin/Manager, 6 digits for Worker) 4. Response is identical whether or not the account exists (prevents enumeration) 5. Rate-limit: max 3 reset requests per account per hour to prevent spam


IDN-UC-09: Manage Own Profile

Actor: Any logged-in user Phase: 1

Any user can update their own display name, change their own password, or change their own PIN while logged in.

Business rules: 1. Changing own password requires entering the current password first 2. Changing own PIN requires entering the current PIN first 3. After a successful password or PIN change, all other active sessions for that user are invalidated (current session remains valid) 4. Display name change takes effect immediately (no re-login required) 5. Users cannot change their own email address or role — only Admin can do this


Business Rules

# Rule
BR-IDN-01 Every request is scoped to a tenant via tenant_id in the JWT. PostgreSQL RLS enforces data isolation — no cross-tenant data access is possible.
BR-IDN-02 Email, when provided, must be unique across all tenants. Null/blank email is always permitted and never compared for uniqueness. Email is required for the Admin role. For all other roles, email is optional.
BR-IDN-03 There is always at least one Admin per tenant. The last Admin cannot have the Admin role removed or be deactivated.
BR-IDN-04 Users cannot be deleted — only deactivated. Historical attribution in audit logs must be preserved.
BR-IDN-05 JWT is short-lived (15 min). Refresh tokens rotate on use (7-day validity).
BR-IDN-06 Audit log is immutable and must be retained for at least 5 years.
BR-IDN-07 Subscription suspension blocks all user logins including Admin — email notification sent before suspension triggers (if Admin has email).
BR-IDN-08 Authentication is handled via the AuthProvider abstraction. Phase 1 uses LocalPasswordProvider (bcrypt). Additional providers can be added without changes to JWT issuance.
BR-IDN-09 Username is the primary login identifier; email is optional. Admin/Manager require password (min 12 chars) or PIN; Worker uses PIN or birth_date + PIN.
BR-IDN-10 Failed login counter resets to 0 on successful login.
BR-IDN-11 Invitation links expire after 48 hours. Admin can resend (generates new link, invalidates old).
BR-IDN-12 Worker accounts without email: Admin sets temporary PIN; worker forced to change on first login.

Out of Scope

  • Specific OAuth providers (Google, Microsoft, etc.) → Phase 2; pluggable via AuthProvider abstraction; specific providers TBD
  • Single Sign-On (SSO / SAML) → not in scope
  • 2FA / MFA → not in Phase 1; may be added in Phase 3
  • Custom roles → not in scope; 8 predefined roles only
  • User groups → not in scope
  • IP allow-listing → not in scope
  • Audit log export → deferred; will be specced separately when regulatory export format is confirmed
  • Offline / tablet mode → not in scope

Open Questions

# Question Impact
OQ-IDN-01 Resolved: Technologist sees full cost breakdown — same visibility as Manager for guide_price and cost calculations (read-only). Scope of Technologist role — closed
OQ-IDN-02 Resolved: No read-only Sales Rep role. 8 predefined roles are sufficient. Defer if a customer explicitly requests it. RBAC granularity — closed
OQ-IDN-03 Resolved: No grace period after explicit cancellation. Login blocks immediately on cancellation. Data preserved for 5 years. Customer trust — closed