At a Glance
Persona: Audit / Config (Auditor read-only + System Administrator config) · Module: vendor-pricelist · Scenarios: ~34
Categories: Happy Path · Permission · Validation · Edge Case
E2E coverage: none — audit-log query and configuration surfaces exercised at API / integration level pending roadmap item; no dedicated spec in../carmen-inventory-frontend-e2e/
This page captures the test scenarios that the Audit / Config persona axis directly drives in the vendor-pricelist module. Two distinct roles sit on this axis: the Auditor (read-only across the full procurement-pricing chain — Template → Campaign → Invitation → Vendor Portal Submission → Pricelist Approval → downstream PR / PO / GRN consumption), who uses every tier's activity log, the application-derived campaign / invitation statuses, the validation engine output stored in tb_pricelist.info, the portal-token telemetry written as system comments on the invitation row, and the cross-document bridges to verify policy compliance, segregation of duties (VPL_AUTH_014), validation-engine integrity, and traceability end-to-end; and the System Administrator (configuration only), who owns the pricelist numbering scheme, the RBAC role-to-permission map for VPL_AUTH_001–VPL_AUTH_015, the portal-token policy, the email-integration wiring, the validation-rule registry, the currency / FX rate sources consumed by Finance, the audit-log retention policy, and the per-invitation token-revocation right (VPL_AUTH_015). Neither role transitions a pricelist across enum_pricelist_status: the Auditor exits via a generated report (no document state change), the Sysadmin exits via a saved configuration with an effective_from timestamp (existing documents retain their snapshotted configuration; new documents use the new configuration). The Sysadmin's only direct touch on a transactional document is the token revocation, which mutates tb_request_for_pricing_detail.pricelist_url_token and appends a system comment, but does not change pricelist status. Scenarios are grouped into the happy paths described in 03-user-flow-audit-config.md, the RBAC boundary that separates read-only-audit from configure-only-sysadmin from no-direct-transact, the validation rules around snapshot preservation, export approval, and configuration race conditions, and a small set of edge cases around in-flight boundaries, rollback, deadlock prevention, and the validation-rule registry. No dedicated audit-config E2E spec exists at this time; coverage is at the API / integration level pending the roadmap item in ../carmen/docs/vendor-pricelist-management/tasks.md.
| # | Scenario | Pre-condition | Steps | Expected |
|---|---|---|---|---|
| VPL-AUD-HP-01 | Auditor queries pricelists by date range | Auditor auditor@blueledgers.com logged in with read-only role; at least 30 pricelists created between 2026-04-01 and 2026-04-30 across multiple vendors / currencies / statuses |
1. Sidebar → Audit workspace → Pricelist Activity Queries. 2. Select template "All pricelists in period". 3. Set created_at filter = 2026-04-01 .. 2026-04-30. 4. Apply. |
Result table renders one row per pricelist with pricelist_no, vendor, currency, status, last action, submitted_at. Empty filter set would have been rejected (see VPL-AUD-VAL-04); date range applied successfully. No tb_pricelist row is mutated. The query is logged to the audit-side activity store with the Auditor's identity. |
| VPL-AUD-HP-02 | Auditor drills into one pricelist and walks its activity log | Auditor logged in; pricelist PL-AUD-01 exists with full lifecycle: vendor portal opened, drafted, submitted, approved by Manager, currently active |
1. From VPL-AUD-HP-01 result set, click PL-AUD-01. 2. Open Activity Log tab. 3. Open Related Documents tab. 4. Expand each lifecycle entry. |
Activity Log shows: portal first-access (invitation-row system comment), tb_pricelist insert at draft, auto-save entries, submitted_at write (VPL_POST_016), Purchaser review, Purchasing Manager signoff (VPL_AUTH_005), VPL_POST_017 activation. Related Documents shows the originating campaign + template + invitation row, plus the downstream PR lines that defaulted from this pricelist and the GRNs that ran variance against it. Pricelist state unchanged. |
| VPL-AUD-HP-03 | Auditor follows the back-chain — PR / PO line → active pricelist | Auditor walking a posted GRN's price variance; needs to verify the pricelist anchor used at the PR-line creation moment | 1. Open the GRN line in the Audit chain view. 2. Click the linked PO line → linked PR line → pricelist_detail_id reference. 3. Open tb_pricelist_detail row. 4. Verify the pricelist status = active at PR-creation time (snapshot semantics) and the price match. |
Chain renders contiguously. The PR line's pricelist_detail_id resolves to a specific row on tb_pricelist_detail; the auditor verifies the pricelist's lifecycle history showed active at the PR-creation timestamp; even if the pricelist is now inactive / expired, the snapshot integrity is preserved. Segregation of duties verified: vendor user holding the portal token ≠ Carmen user who approved the pricelist (VPL_AUTH_014). |
| VPL-AUD-HP-04 | Auditor verifies validation engine output | Pricelist PL-V-Q with info.quality_score = 65 (below default tenant threshold 70); approved by Purchasing Manager with a Manager-override system comment |
1. Open PL-V-Q. 2. Open the Validation panel. 3. Read info.validation_results and info.quality_score. 4. Open the activity log; find the Manager-override system comment. 5. Verify Manager has VPL_AUTH_005 rights. |
Validation output renders read-only per VPL_XMOD_009. Quality score 65 < 70 would normally route to Manager-only approval; the Manager-override comment captures the rationale (e.g., "New vendor entering the catalogue — accepting initial low score with re-collection in 60 days"). Auditor records no finding if the rationale is documented; otherwise flags the override for review. |
| VPL-AUD-HP-05 | Auditor exports a period report with secondary approval | Result set from VPL-AUD-HP-01 includes sensitive fields (vendor identities, pricing detail, portal-token telemetry); data-export approver export.approver@blueledgers.com available |
1. Click Export → CSV (full detail). 2. System materialises the request in pending state. 3. Export approver reviews scope. 4. Approver clicks Release. 5. Auditor downloads CSV. | Export request enters pending with Auditor identity, filter set, sensitive-field manifest. Export approver review log records approver identity + decision. On release, the CSV is materialised and a download link is recorded in the audit case file with the approver's identity. The export itself is an audit object — visible only inside the case file until released. No pricelist state change. |
| VPL-AUD-HP-06 | Sysadmin adjusts pricelist numbering scheme | Sysadmin sysadmin@blueledgers.com logged in; change ticket links Finance memo approving new year-prefix PL-2026-NNNNN; current scheme is PL-NNNNN |
1. Configuration → Pricelist Numbering & Templates. 2. Open the active scheme. 3. Change prefix to PL-2026-, sequence width = 5, reset rule = yearly. 4. Preview next-issued pricelist_no. 5. Save. |
Preview shows next-issued pricelist_no = PL-2026-00001. On save, configuration is written with effective_from = now(); configuration audit log records the version diff. Pricelists already draft / active / inactive retain their original pricelist_no (snapshot semantics); new pricelists created after effective_from issue under the new scheme. No tb_pricelist row is mutated. |
| VPL-AUD-HP-07 | Sysadmin tightens portal-token policy (expiration shortened) | Sysadmin logged in; change ticket from Compliance requests reducing default token expiration from 30 days to 14 days; one campaign currently active with vendors mid-submission | 1. Configuration → Portal Token Policy. 2. Find default-expiration setting. 3. Change from 30 days to 14 days. 4. Preview affected-token count. 5. Save. |
Preview shows: in-flight tokens count, new-token count expected over the next 30 days. On save, configuration writes with effective_from = now(). In-flight tokens retain their snapshotted 30-day expiration; only newly-issued tokens (from campaigns launched after effective_from) inherit the 14-day expiration. The configuration audit log records the change and the snapshotted in-flight count. |
| VPL-AUD-HP-08 | Sysadmin revokes a compromised portal token | Sysadmin logged in; vendor V_compromised reported email account hacked; their portal token must be invalidated immediately |
1. Open the campaign → find V_compromised's invitation row. 2. Click Revoke Token. 3. Confirm with second-factor / step-up auth. 4. Enter reason: "Vendor email compromise — re-issue under separate campaign." |
VPL_AUTH_015 exercised. tb_request_for_pricing_detail.pricelist_url_token = NULL; revocation system comment in tb_request_for_pricing_detail_comment captures actor + reason + second-factor verification reference. Vendor's next portal access returns 401 — token revoked; any in-progress draft pricelist (if exists) remains at draft for the Purchaser's decision. Invitation status moves to derived expired. |
| VPL-AUD-HP-09 | Sysadmin adds a new business rule to the validation registry | Sysadmin logged in; change ticket requests adding a new rule "Lead-time must not exceed 90 days for non-imported products" | 1. Configuration → Validation Rule Registry. 2. Click Add Rule. 3. Fill name = LEAD_TIME_CAP, category = supply-chain, condition = lead_time_days <= 90 AND product.is_imported = false, action = reject. 4. Preview impact against the last 30 days of submissions. 5. Save. |
Preview shows count of recent submissions that would have failed under the new rule. On save, rule is added to the registry with effective_from = now(). New vendor submissions and Purchaser-side uploads run the rule on save and on submit; existing pricelists do not retroactively fail. Sysadmin's change ticket is closed. Auditor can subsequently verify rule firing via the activity log on new submissions. |
| VPL-AUD-HP-10 | Sysadmin reconfigures FX rate source | Sysadmin logged in; tenant moves from FX provider A to FX provider B; Finance Manager has approved the change | 1. Configuration → Currency & FX Sources. 2. Open the active FX source. 3. Change endpoint URL + auth credentials. 4. Run connectivity probe. 5. Save (probe-and-cutover sequence). | Probe succeeds; cutover atomic. Configuration written with effective_from = now(); configuration audit log records the change. Pricelists already at active retain their snapshot of the FX source at activation time for any FX computation downstream; new computations (e.g., new variance audit by Finance) use the new source. If the probe fails, the save is held and the prior source remains in force; the Sysadmin is notified to remediate. |
| # | Scenario | Expected behaviour (allow/deny + reason) |
|---|---|---|
| VPL-AUD-PERM-01 | Auditor opens any pricelist / campaign / invitation in any status (read-only across the chain) | Allow per VPL_AUTH_013. The Auditor can open every tier across all statuses including terminal (active, inactive, expired, soft-deleted). UI exposes no edit / approve / reject / inactivate / revoke actions. Direct API edit calls return "Read-only role — write actions are not permitted from the Audit workspace." |
| VPL-AUD-PERM-02 | Auditor attempts a write action (edit a detail row, comment as actor on tb_pricelist_comment, revoke a token) |
Deny. The Auditor has no write surface in the module — not on the three tiers, not on the comment tables (other than the audit-side case file, a separate store), not on the token. UI hides write actions; direct API attempts return "Read-only role — write actions are not permitted from the Audit workspace." Audit-side case-file notes are NOT pricelist module comments. |
| VPL-AUD-PERM-03 | Sysadmin opens any configuration surface (numbering, RBAC, portal-token policy, email integration, validation rules, currency / FX sources, audit retention) | Allow per VPL_AUTH_012. Each save is recorded in the configuration audit log with Sysadmin's identity, the version diff, the effective_from timestamp, and any affected-population count from the preview panel. |
| VPL-AUD-PERM-04 | Sysadmin attempts to create / approve / activate / inactivate a pricelist from the configuration workspace | Deny — segregation. The Sysadmin role configures the rules but does NOT transact on them. Per VPL_AUTH_001–VPL_AUTH_006 (Purchaser scope) and VPL_AUTH_004–VPL_AUTH_005 (Manager scope), the Sysadmin is not in any of these subjects. UI does not expose pricelist transactional actions in the configuration workspace; direct API attempts return "Sysadmin role cannot transact in the vendor-pricelist module — use the Purchaser or Purchasing Manager role." The token-revocation action (VPL-AUD-HP-08) is the documented exception. |
| VPL-AUD-PERM-05 | Sysadmin revokes a portal token via VPL_AUTH_015 |
Allow with second-factor / step-up auth required. This is the only direct touch the Sysadmin has on a transactional document. The action writes a mandatory reason to tb_request_for_pricing_detail_comment and to the configuration audit log for cross-reference. |
| VPL-AUD-PERM-06 | Purchasing Manager revokes a portal token via VPL_AUTH_015 |
Allow per the dual-authority on token revocation. Same shape as Sysadmin revocation: second-factor required, mandatory reason. The Manager's path is typically driven by a Purchaser escalation per 03-user-flow-purchaser.md § 3. |
| VPL-AUD-PERM-07 | Auditor requests an export including sensitive fields | Allow — with secondary approval gate. Per the data-export policy, exports including sensitive fields enter pending state; the Auditor cannot bypass. An export approver releases the export. VPL-AUD-HP-05 walks the happy path; VPL-AUD-VAL-02 covers the unapproved case. |
| VPL-AUD-PERM-08 | A user who is neither Auditor nor Sysadmin (e.g., Purchaser, Finance Officer) opens the Audit workspace or the Configuration workspace | Deny. Per RBAC, only users with the Auditor role can open the Audit workspace and only users with the Sysadmin role can open the Configuration workspace. UI hides both sidebar entries; direct URL navigation returns "Audit workspace requires the Auditor role." / "Configuration workspace requires the System Administrator role." Transactional personas have their own activity views on the pricelist record but cannot open the cross-document audit query builder. |
| VPL-AUD-PERM-09 | Sysadmin executes an elevated escalation on a deadlocked / orphaned pricelist (e.g., approve under emergency override) | Deny — Manager-only. Unlike PO module's PO_AUTH_007 Sysadmin elevated void path, the vendor-pricelist module does not grant the Sysadmin any elevated transactional path — the deadlock remediation (Manager-approval, inactivation, fresh campaign) lives entirely on the Manager / Purchaser side. The Sysadmin's elevated tool is configuration (e.g., emergency RBAC change adding a temporary approver) or token revocation. |
| # | Scenario | Trigger | Expected error |
|---|---|---|---|
| VPL-AUD-VAL-01 | Sysadmin changes config while pricelists are in flight — snapshot preserved | Pricelist PL-SP-01 at status = draft + submitted_at IS NOT NULL (in Purchaser review) under the OLD high-value threshold of ฿1,000,000; Sysadmin changes the threshold to ฿2,000,000 while PL-SP-01 is mid-review |
The save is allowed. PL-SP-01 continues under its snapshotted threshold and routing; its approval path does not retroactively change. Preview panel surfaces the affected-pricelist count before save. Configuration audit log records the change and the in-flight count. On save, new pricelists created after effective_from use the new ฿2,000,000 threshold. No tb_pricelist mutation from the config save. |
| VPL-AUD-VAL-02 | Export approval bypass attempted | Auditor requests CSV export including sensitive fields; data-export approver has NOT approved | Reject the download. Server returns "Export requires approval — sensitive fields detected (vendor identity, pricing snapshot, portal-token telemetry). Export is in pending state until release by an export approver." Download link is not generated; pending export remains in the case file. Direct API call to materialise returns 403 Forbidden — approval required. |
| VPL-AUD-VAL-03 | Sysadmin attempts to save a portal-token policy that would expose a security gap | Sysadmin sets default token expiration to 9999 days, removes IP allowlist entirely, and sets concurrent-session limit to 0 (unlimited) |
Reject the save. Server returns "Portal token policy violates tenant security baseline — expiration must be <= 365 days; concurrent-session limit must be 1..100; removing the IP allowlist requires Compliance approval." (Tenant-configurable security baselines guard against accidental relaxation.) Configuration audit log records the rejected attempt. |
| VPL-AUD-VAL-04 | Auditor submits an empty filter set on a date-range query | Auditor opens Audit → Pricelist Activity Queries; clicks Apply without setting any filter | Reject the query. Server returns "Empty filter set — at least one of date range, vendor, currency, or business unit must be specified to prevent unbounded scans." No result set is rendered; no audit-side activity-store entry written. |
| VPL-AUD-VAL-05 | Sysadmin attempts to delete a referenced master-data record (e.g., a currency referenced by an active pricelist) | Sysadmin opens Configuration → Currency & FX Sources; tries to remove EUR from the permitted-currency list while at least one active pricelist has currency_id = EUR |
Reject the removal. Server returns "Cannot remove currency EUR — referenced by N active pricelist(s). Archive the currency setting instead to preserve historical references." Archive flow is the only acceptable path: archived currencies remain valid on historical pricelist snapshots but are not selectable for new submissions. This preserves the calculation-rule integrity in VPL_CALC_005 for in-flight pricelists. |
| VPL-AUD-VAL-06 | Sysadmin's validation-rule change would cause in-progress submissions to fail | Sysadmin tries to add a rule "Lead-time <= 7 days" that would invalidate 30+ in-progress vendor portal sessions | Preview flags the impact: "Saving this rule change will cause N in-progress vendor portal sessions to receive a new validation error on their next save." Sysadmin can (a) cancel, (b) defer to a window with no in-progress submissions, or (c) save with the warning acknowledged. If saved, the rule fires on next save / submit; the configuration audit log captures the impacted session count and the Sysadmin's acknowledgement. |
| VPL-AUD-VAL-07 | Sysadmin attempts to revoke a portal token without entering a reason | Sysadmin opens the Revoke action; tries to confirm without entering reason text | Reject — reason is mandatory per VPL_AUTH_015 audit requirement. Server returns "Token revocation requires a reason to be recorded in the system comment." UI does not enable Confirm until reason is populated; direct API call is rejected. |
| VPL-AUD-VAL-08 | Sysadmin attempts to deactivate the only IP allowlist entry while in-flight portal sessions exist | Sysadmin removes the last IP from the allowlist, leaving the allowlist empty in enforce mode (≠ disable allowlist) | Reject the save. Server returns "Empty IP allowlist in enforce mode would block all vendor portal access. Either add another IP, disable the allowlist, or accept the disable mode explicitly." Configuration audit log records the rejected attempt. |
| # | Scenario | Condition | Expected |
|---|---|---|---|
| VPL-AUD-EDGE-01 | In-flight snapshot boundary — config saved exactly at submission | Pricelist PL-SB-01 is at submitted_at = NULL; vendor clicks Submit at T; Sysadmin saves a validation-rule change with effective_from = T (same millisecond) |
Race resolved by atomic effective_from comparison. If PL-SB-01's VPL_POST_016 write timestamp is strictly less than effective_from, the submission captures the OLD validation rule snapshot; if >= effective_from, the submission runs the new rule. The pricelist's tb_pricelist_comment activity log first entry records the validation-rule version bound to, so the audit chain is unambiguous. Configuration audit log records the in-flight submission count at the boundary. |
| VPL-AUD-EDGE-02 | Rollback of a bad config change | Sysadmin saves a new RBAC config at T1; verification finds that a needed approver role was inadvertently removed; Sysadmin reverts to the prior version at T2 > T1 |
Rollback is itself a configuration save with effective_from = T2. Pricelists created between T1 and T2 are NOT retroactively re-evaluated (snapshot semantics); they continue under the broken-RBAC snapshot — typically rescued via one-off delegation or emergency RBAC patch. Pricelists created after T2 use the rolled-back configuration. Configuration audit log retains BOTH versions. |
| VPL-AUD-EDGE-03 | Audit-log gap — missing system event on activation | Auditor walks PL-GAP-01's timeline; finds tb_pricelist_comment has the submitted-at entry at T0 and the activation entry at T2 but is MISSING the validator-output write at T1 (which should sit between them) |
The gap is itself an audit finding. The Auditor flags PL-GAP-01 in the case file with a "missing validator-output system entry" note, attaches the timeline excerpt + the expected validator-comment count, and routes to the Sysadmin for investigation. Possible causes: replay-log corruption, validator-bypass code path, or a comment that was inadvertently soft-deleted. The Auditor does NOT close the case as "no findings"; the case stays open until the gap is explained. |
| VPL-AUD-EDGE-04 | Mass token-revocation event | Sysadmin discovers an email-account-takeover incident affecting 20+ vendors in an active campaign; needs to revoke all affected tokens | Sysadmin uses the bulk-revoke action: filter the campaign's invitation rows by contact_email IN (compromised-list); click Revoke selected. Each revocation writes its own tb_request_for_pricing_detail_comment system entry and counts to the configuration audit log. Atomic — either all 20+ revocations succeed or none does (transactional). Per VPL_AUTH_015, second-factor is required once for the bulk action. The configuration audit log records the bulk event with all 20+ token references. |
| VPL-AUD-EDGE-05 | Query timeout on a huge dataset | Auditor sets date range = 2024-01-01 .. 2026-05-15 (29 months) + no other filter; tenant has 50,000+ pricelists in scope |
Query hits the date-range scan limit (VPL-AUD-VAL-04 prevents the empty case, but a 29-month single-filter still risks timeout). System chunks the query — first returns 1,000 rows + a "Continue to next page" cursor, persists the query plan, runs the remainder asynchronously. The Auditor can page through synchronously or schedule a full-extract export (which then enters the VPL-AUD-HP-05 / VPL-AUD-VAL-02 export-approval flow). No timeout error; experience degrades gracefully. |
| VPL-AUD-EDGE-06 | Config save vs in-flight submission race | Sysadmin clicks Save on a new validation rule at T; simultaneously, 5 vendors click Submit on their portal sessions in adjacent windows; all 6 actions arrive at the backend within the same 500 ms window |
Backend serialises by effective_from timestamp on the configuration row and the VPL_POST_016 write timestamp on each pricelist. Each submission is atomically tagged with the validation-rule-set version active at the instant of its VPL_POST_016 write. Of the 5 submissions, some may capture the OLD rule set and some the NEW; each pricelist's tb_pricelist_comment first entry unambiguously records WHICH version it bound to. No submission ends up in a hybrid state; no submission is rejected as "rule set in transition." |
| VPL-AUD-EDGE-07 | Validation-rule retroactive review | Sysadmin adds rule LEAD_TIME_CAP at T; six weeks later Auditor reviews recent submissions and notices the rule was inadvertently bypassed on three submissions (the validator's comment shows the rule was not evaluated) |
Audit finding: rule registry inclusion was correct but the validator's selection logic had a bug that excluded the rule for a particular vendor-category combination. Auditor flags the three submissions, files a case-file note, and routes to Engineering via the Sysadmin. The three affected pricelists remain at their current statuses; no retroactive invalidation. The rule fix is deployed and validated; the audit case file retains the evidence trail. |
X-VPL-* scenarios. X-VPL-07 (token revocation race) and X-VPL-11 (Sysadmin config change preserves in-flight snapshot) are the explicit handoff scenarios with this axis.VPL_AUTH_009 (Finance Officer read-only — same pattern Auditor inherits in scope), VPL_AUTH_011 (Receiver read-only — same pattern), VPL_AUTH_012 (Sysadmin configures policy and integration; covered in VPL-AUD-PERM-03), VPL_AUTH_013 (Auditor read-only across the chain; covered in VPL-AUD-PERM-01 / VPL-AUD-PERM-02), VPL_AUTH_014 (segregation of duties — verified by Auditor in chain audit per VPL-AUD-HP-03), VPL_AUTH_015 (token revocation — Sysadmin / Manager action covered in VPL-AUD-HP-08 / VPL-AUD-PERM-05 / VPL-AUD-PERM-06). § 5 — VPL_POST_021 (auto-expire cron — Sysadmin configures schedule, Auditor verifies executions), VPL_POST_014 (invitation auto-expire — same). § 6 — VPL_XMOD_009 (validation engine contract — Sysadmin configures the rule registry; Auditor verifies the engine actually ran them per VPL-AUD-HP-04 / VPL-AUD-EDGE-07), VPL_XMOD_008 (currency master — Sysadmin's FX configuration; Auditor's cross-currency chain audit), VPL_XMOD_006 (product master — orphan hygiene reports audited).VPL_POST_005–VPL_POST_014) the Auditor consumes.../carmen/docs/vendor-pricelist-management/VENDOR_MANAGEMENT_TECHNICAL_SPECIFICATION.md — RBAC matrix used in Section 2 and tied to the VPL_AUTH_001–VPL_AUTH_015 rule family.../carmen/docs/vendor-pricelist-management/requirements.md § Requirement 28 (Advanced Portal Session Management) — carmen/docs source for the portal-token policy surface (VPL-AUD-HP-07).../carmen/docs/vendor-pricelist-management/design.md § Phase 6 (Data Validation & Quality Control) — the validation-rule registry surface configured in VPL-AUD-HP-09.../carmen/docs/vendor-pricelist-management/tasks.md covers the future dedicated coverage; the SKIP_NOTE_BACKEND annotation pattern from the PO module (401-po.spec.ts) applies similarly here for configuration-driven behaviour (numbering generation, RBAC enforcement, token policy, validation rule firing) which is validated via the audit logs the Auditor walks and the configuration audit log the Sysadmin writes.