Skip to content

SDK-2616: .NET - Support configuration for IDV shortened flow - dotnet#543

Open
mehmet-yoti wants to merge 1 commit into
masterfrom
websdk-auto/SDK-2616-dotnet-net---support-configuration-for-idv-shortened-flow
Open

SDK-2616: .NET - Support configuration for IDV shortened flow - dotnet#543
mehmet-yoti wants to merge 1 commit into
masterfrom
websdk-auto/SDK-2616-dotnet-net---support-configuration-for-idv-shortened-flow

Conversation

@mehmet-yoti
Copy link
Copy Markdown
Contributor

Summary

Adds support for configuring the IDV shortened flow by allowing callers to suppress individual screens in the Doc Scan SDK config (SDK-2616). Introduces a new suppressed_screens field on SdkConfig, fluent builder methods, a constants class for valid screen identifiers, and a helper to check whether a given screen is suppressed.

Changes

  • src/Yoti.Auth/DocScan/Session/Create/SdkConfig.cs: Added SuppressedScreens property serialized as suppressed_screens (omitted when null), a new optional constructor parameter, and an IsScreenSuppressed(string) helper for case-sensitive membership checks.
  • src/Yoti.Auth/DocScan/Session/Create/SdkConfigBuilder.cs: Added WithSuppressedScreens(List<string>) (bulk set/reset) and WithSuppressedScreen(string) (append single) fluent methods; wired the field into Build().
  • src/Yoti.Auth/DocScan/Session/Create/SuppressedScreen.cs: New static class exposing valid screen identifier constants (ID_DOCUMENT_EDUCATION, ID_DOCUMENT_REQUIREMENTS, SUPPLEMENTARY_DOCUMENT_EDUCATION, ZOOM_LIVENESS_EDUCATION, STATIC_LIVENESS_EDUCATION, FACE_CAPTURE_EDUCATION, FLOW_COMPLETION).
  • test/Yoti.Auth.Tests/DocScan/Session/Create/SdkConfigBuilderTests.cs: Added 12 unit tests covering default null behaviour, bulk-set, empty list, null reset, incremental append, constant values, IsScreenSuppressed happy path / unlisted / null / case sensitivity, JSON array serialization, and JSON omission when null.

QA Test Steps

  1. Setup: Check out the branch and build the solution (dotnet build src/Yoti.Auth.sln).
  2. Run unit tests: dotnet test test/Yoti.Auth.Tests/Yoti.Auth.Tests.csproj --filter "FullyQualifiedName~SdkConfigBuilderTests" – verify all 12 new SuppressedScreen* / IsScreenSuppressed* tests pass alongside existing tests.
  3. Happy path (bulk set): In a sample app, build new SdkConfigBuilder().WithSuppressedScreens(new List<string>{ SuppressedScreen.IdDocumentEducation, SuppressedScreen.FlowCompletion }).Build(), serialize with JsonConvert.SerializeObject, and confirm the JSON contains "suppressed_screens":["ID_DOCUMENT_EDUCATION","FLOW_COMPLETION"].
  4. Happy path (incremental): Chain .WithSuppressedScreen(SuppressedScreen.ZoomLivenessEducation).WithSuppressedScreen(SuppressedScreen.FaceCaptureEducation), build, and confirm both entries appear in SdkConfig.SuppressedScreens in insertion order.
  5. Default / omission: Build an SdkConfig without calling either suppression method; confirm SuppressedScreens is null and the serialized JSON does not contain a suppressed_screens key (driven by NullValueHandling.Ignore).
  6. Reset via null: Call .WithSuppressedScreens(listOfOne).WithSuppressedScreens(null).Build() – confirm SuppressedScreens is null.
  7. Empty list: Call .WithSuppressedScreens(new List<string>()) – confirm the property is non-null, count 0, and serializes as "suppressed_screens":[].
  8. IsScreenSuppressed checks:
    • Returns true when the screen is in the list.
    • Returns false when not in the list.
    • Returns false when SuppressedScreens is null (no NRE).
    • Returns false for differing case (e.g. "id_document_education").
  9. End-to-end regression: Create a Doc Scan session via DocScanClient.CreateSession against a sandbox/test environment using a config that suppresses ID_DOCUMENT_EDUCATION, launch the Web SDK flow, and confirm that education screen is skipped while all other screens behave as before.
  10. Regression – existing fields: Build an SdkConfig populating all previously existing fields (AllowedCaptureMethods, PrimaryColour, AllowHandoff, AttemptsConfiguration, etc.) without suppressed screens and confirm serialized output matches the pre-change baseline (no new keys, existing keys unchanged).

Notes

  • Screen identifiers are modelled as string constants on a static SuppressedScreen class rather than an enum, matching the existing pattern used by DocScanConstants in this SDK and allowing backend-driven additions without a breaking enum change. Callers can therefore pass arbitrary strings; validation of unknown values is deferred to the backend.
  • SuppressedScreens is serialized with NullValueHandling.Ignore, so the field is omitted entirely when unset – preserving backwards compatibility for existing integrations that do not use the shortened flow.
  • An empty list is serialized as [] (not omitted); backend should treat this as "suppress nothing," matching the default behaviour.
  • IsScreenSuppressed performs a case-sensitive exact-string match, consistent with how the backend compares identifiers. If case-insensitive matching is later required, it can be added without breaking the current contract.
  • No changes to public constructors were made in a breaking way – the new suppressedScreens parameter on SdkConfig is optional (= null) and appended at the end of the argument list.

Related Jira: SDK-2616
Auto-generated by n8n + Claude CLI

@mehmet-yoti
Copy link
Copy Markdown
Contributor Author

🤖 Claude Code Review

Code Review Findings

Critical

None

Major

  • src/Yoti.Auth/DocScan/Session/Create/SuppressedScreen.cs:1-17 — The screen-name constants live directly under Yoti.Auth.DocScan.Session.Create as a new top-level static class, while every other DocScan string-constant collection in the codebase is centralized in src/Yoti.Auth/Constants/DocScanConstants.cs (e.g. Camera, CameraAndUpload, Zoom, Static, FaceCapture). This is an inconsistency and a public-API divergence that splits knowledge of which class to import. Suggested fix: move the constants into DocScanConstants (e.g. SuppressedScreenIdDocumentEducation) to match the pattern used by every other IDV enum-like string set, or put it under Yoti.Auth.Constants alongside Extension/UserProfile (both scoped static string classes sibling to DocScanConstants). Update callers/tests and XML-doc <see cref> accordingly.

Minor

  • src/Yoti.Auth/DocScan/Session/Create/SdkConfigBuilder.cs:254-258WithSuppressedScreens(List<string>) replaces previously accumulated entries while WithSuppressedScreen(...) appends. The mixed semantics are tested but undocumented. Suggested fix: add a <remarks> to WithSuppressedScreens stating "Replaces any previously set value (including entries added via WithSuppressedScreen)." and mirror on WithSuppressedScreen noting it appends.
  • src/Yoti.Auth/DocScan/Session/Create/SdkConfigBuilder.cs:265-272WithSuppressedScreen(string) does not guard against null/empty, so null/"" gets appended and serialized to the backend. Suggested fix:
    if (string.IsNullOrEmpty(suppressedScreen))
        throw new ArgumentException("suppressedScreen cannot be null or empty", nameof(suppressedScreen));
    and add a corresponding unit test.
  • test/Yoti.Auth.Tests/DocScan/Session/Create/SdkConfigBuilderTests.cs:371-374SuppressedScreensShouldSerializeToJsonArray asserts ordering by index access, which is fragile. Suggested fix: use Assert.IsTrue(array.Select(t => t.ToString()).SequenceEqual(screens)) or CollectionAssert.AreEqual(...) for clearer intent.

Nit

  • src/Yoti.Auth/DocScan/Session/Create/SdkConfig.cs:44NullValueHandling = NullValueHandling.Ignore on the attribute is redundant with the global DocScanService.YotiDefaultJsonSettings. Other nullable fields (e.g. AllowHandoff) rely on the global setting. Suggested fix: drop the per-attribute flag for consistency, or apply it to AllowHandoff too.
  • src/Yoti.Auth/DocScan/Session/Create/SdkConfig.cs:1 — File lost its UTF-8 BOM while sibling files still start with using. Suggested fix: re-save as UTF-8-with-BOM to match repo convention and avoid blame churn.
  • src/Yoti.Auth/DocScan/Session/Create/SdkConfig.cs:92 & SdkConfigBuilder.cs:295 — Inconsistent trailing-newline handling between the two edited files. Suggested fix: pick one convention and apply to both.
  • src/Yoti.Auth/DocScan/Session/Create/SdkConfig.cs:87-90IsScreenSuppressed uses List.Contains (O(n)); fine for ≤7 items. Suggested fix: add a brief XML-doc remark noting it's not intended for hot-loop use, or leave as-is.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support in the Doc Scan .NET SDK for configuring the IDV “shortened flow” by allowing specific screens to be suppressed via SdkConfig.

Changes:

  • Added suppressed_screens to SdkConfig (nullable/omitted when unset) and an IsScreenSuppressed(string) helper.
  • Extended SdkConfigBuilder with fluent APIs to set/append suppressed screens and wired it into Build().
  • Introduced SuppressedScreen constants and added unit tests covering builder behavior + JSON serialization/omission.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/Yoti.Auth/DocScan/Session/Create/SdkConfig.cs Adds SuppressedScreens serialization + helper to check suppression.
src/Yoti.Auth/DocScan/Session/Create/SdkConfigBuilder.cs Adds builder methods for setting/appending suppressed screens and passes through to SdkConfig.
src/Yoti.Auth/DocScan/Session/Create/SuppressedScreen.cs Adds constants for known suppressible screen identifiers.
test/Yoti.Auth.Tests/DocScan/Session/Create/SdkConfigBuilderTests.cs Adds unit tests for suppressed screens behavior and JSON output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +254 to +258
public SdkConfigBuilder WithSuppressedScreens(List<string> suppressedScreens)
{
_suppressedScreens = suppressedScreens;
return this;
}
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WithSuppressedScreens assigns the provided list directly without validating its contents. If the list contains null/empty/whitespace entries, JSON serialization will include null/invalid identifiers in suppressed_screens, which is likely to cause backend validation errors. Consider validating each element (and optionally de-duplicating) or throwing an InvalidOperationException/ArgumentException when invalid entries are provided.

Copilot uses AI. Check for mistakes.
Comment on lines +267 to +270
if (_suppressedScreens == null)
_suppressedScreens = new List<string>();

_suppressedScreens.Add(suppressedScreen);
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WithSuppressedScreen will add the provided value even when it is null/empty/whitespace. That can produce a suppressed_screens array containing null in the serialized config, which is likely invalid and may cause session creation to fail. Add input validation (and consider ignoring duplicates) before appending to the list.

Suggested change
if (_suppressedScreens == null)
_suppressedScreens = new List<string>();
_suppressedScreens.Add(suppressedScreen);
if (string.IsNullOrWhiteSpace(suppressedScreen))
return this;
if (_suppressedScreens == null)
_suppressedScreens = new List<string>();
if (!_suppressedScreens.Contains(suppressedScreen))
_suppressedScreens.Add(suppressedScreen);

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants