Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ updates:
directory: "/"
schedule:
interval: "weekly"
target-branch: main
target-branch: develop
commit-message:
prefix: "ci: "
49 changes: 23 additions & 26 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,6 @@ on:
- '**.md'
tags-ignore:
- '**'
pull_request_target:
branches:
- 'main'
- 'develop'
paths-ignore:
- '**.md'
tags-ignore:
- '**'

env:
COREHOST_TRACE: false
Expand All @@ -37,6 +29,11 @@ env:
# Do not generate summary otherwise it leads to duplicate errors in build log
DOTNET_BUILD_ARGS: /consoleloggerparameters:NoSummary /property:GenerateFullPaths=true

TEST_CREDITS_JSON: ${{ secrets.TEST_CREDITS_JSON }}
SONAR_SECRET: ${{ secrets.SONAR_SECRET }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

defaults:
run:
shell: pwsh
Expand All @@ -62,11 +59,11 @@ jobs:
- { name: 'Windows .NET 4.6', os: windows-latest, framework: 'net462', net-sdk: '8.0.x', target: 'net462' }

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
fetch-depth: 1
fetch-depth: 0
# For pull_request_target (dependabot), checkout the PR head SHA
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.ref }}
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}

- name: Get SDK Version
id: props
Expand All @@ -77,18 +74,18 @@ jobs:
Write-Host "✓ Found SignNow.NET SDK project version: $Version"

- name: Setup JDK 17 (SonarQube requirement)
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '17'

- name: Setup .NET SDK
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ matrix.net-sdk }}

- name: Setup Nuget Cache
uses: actions/cache@v4
uses: actions/cache@v5
id: nuget-cache
with:
path: ~/.nuget
Expand All @@ -102,12 +99,14 @@ jobs:
run: dotnet restore -v:n

- name: Configure signNow API
run: echo '${{ secrets.TEST_CREDITS_JSON }}' >> ${{ github.workspace }}/api-eval.signnow.com.json
run: |
$outPath = Join-Path $Env:GITHUB_WORKSPACE 'api-eval.signnow.com.json'
[IO.File]::WriteAllText($outPath, $Env:TEST_CREDITS_JSON)

- name: Get SonarQube Project Key
id: sonar
run: |
$SonarConfigPath = "${{ github.workspace }}/SonarQube.Analysis.xml"
$SonarConfigPath = Join-Path $Env:GITHUB_WORKSPACE 'SonarQube.Analysis.xml'
if (Test-Path $SonarConfigPath) {
[xml]$SonarConfig = Get-Content $SonarConfigPath
$ProjectKey = $SonarConfig.SonarQubeAnalysisProperties.Property | Where-Object { $_.Name -eq "sonar.projectKey" } | Select-Object -ExpandProperty '#text'
Expand All @@ -121,7 +120,7 @@ jobs:
} else {
Write-Warning "SonarQube configuration file not found: $SonarConfigPath"
}

- name: SonarQube begin
if: steps.sonar.outputs.has-project-key == 'true'
run: |
Expand All @@ -130,8 +129,8 @@ jobs:
/s:${{ github.workspace }}/SonarQube.Analysis.xml `
/v:"${{ steps.props.outputs.version }}" `
/d:sonar.projectBaseDir="${{ github.workspace }}" `
/d:sonar.token="${{ secrets.SONAR_SECRET }}" `
/d:sonar.host.url="${{ secrets.SONAR_HOST_URL }}" `
/d:sonar.token="${{ env.SONAR_SECRET }}" `
/d:sonar.host.url="${{ env.SONAR_HOST_URL }}" `
/d:sonar.scanner.skipJreProvisioning=true

- name: Run Tests on ${{ matrix.framework }} for TargetFramework ${{ matrix.target }} with Coverage
Expand All @@ -145,22 +144,22 @@ jobs:
dotnet build SignNow.Net.Test --configuration Debug --no-incremental `
--framework ${{ matrix.framework }} `
${{ env.DOTNET_BUILD_ARGS }}

dotnet test SignNow.Net.Test --configuration Debug --no-build `
--framework ${{ matrix.framework }} `
--logger:trx --results-directory ./SignNow.Net.Test/TestResults `
/p:CollectCoverage=true

- name: Save Code Coverage Results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: CoverageReports-${{ runner.os }}-${{ matrix.framework }}.zip
path: ${{ env.COVERAGE_PATH }}/**/coverage*

- name: SonarQube end
if: steps.sonar.outputs.has-project-key == 'true'
continue-on-error: true
run: dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_SECRET }}"
run: dotnet-sonarscanner end /d:sonar.token="${{ env.SONAR_SECRET }}"

- name: Test Release Notes parser
if: (runner.os == 'macOS' || runner.os == 'Linux')
Expand All @@ -177,12 +176,10 @@ jobs:
- name: Upload Code Coverage Report (Codecov.io)
if: env.CODECOV_TOKEN != ''
continue-on-error: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
uses: codecov/codecov-action@v5
with:
name: ${{ runner.os }}-codecov-${{ matrix.framework }}
flags: ${{ runner.os }},${{ matrix.target }}
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ env.CODECOV_TOKEN }}
files: ${{ env.COVERAGE_PATH }}/${{ matrix.framework }}/coverage.${{ matrix.framework }}.opencover.xml
fail_ci_if_error: false
21 changes: 13 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ jobs:

defaults:
run:
shell: pwsh
shell: bash
Copy link
Contributor

Choose a reason for hiding this comment

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

I've fixed publish to Nuget step syntax to powershell. Please doublecheck this shell with accordance to run pipeline of Publish Nuget Package step

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i have added shell: pwsh to Publish Nuget Package step, test dotnet nuget push on local folder => it is ok,
so action should work if no issue with secrets


steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Setup .NET 8
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
7.0.x
8.0.x

- name: Setup Nuget Cache
uses: actions/cache@v4
uses: actions/cache@v5
id: nuget-cache
with:
path: ~/.nuget
Expand All @@ -53,8 +53,10 @@ jobs:

- name: Create Release
uses: ncipollo/release-action@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ env.GITHUB_TOKEN }}
name: signNow .Net SDK v${{ steps.get-version.outputs.VERSION }}
tag: ${{ steps.get-version.outputs.VERSION }}
bodyFile: ${{ github.workspace }}/release-notes.txt
Expand All @@ -64,7 +66,10 @@ jobs:

- name: Publish Nuget Package
working-directory: ${{ github.workspace }}/SignNow.Net/bin/Publish
shell: pwsh
env:
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}
run: |
dotnet nuget push SignNow.Net.${{ steps.get-version.outputs.VERSION }}.nupkg \
-k ${{ secrets.NUGET_TOKEN }} \
-s https://api.nuget.org/v3/index.json
dotnet nuget push SignNow.Net.${{ steps.get-version.outputs.VERSION }}.nupkg `
--api-key ${{ env.NUGET_TOKEN }} `
--source https://api.nuget.org/v3/index.json
146 changes: 146 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# SignNow .NET SDK - Architectural Context & Global Guidance

This file establishes the architectural philosophy and coding standards for SignNow .NET SDK.
Applies to every agent session.

## 1. System Identity
**Role:** Principal Software Architect and Technical Archaeologist of a Fortune 500 tech company
**Core Stack:**
- C# SDK built with multi-targeted MSBuild projects (`net462`, `netstandard2.0`, `netstandard2.1`, current modern .NET);
- HttpClient transport wrapped by `ISignNowClient`/`IHttpContentAdapter`;
- Newtonsoft.Json serialization;
- MSTest/xUnit-style suites under `SignNow.Net.Test`; shared configuration via `Directory.Build.props`, `SignNow.props`, and `netfx.props`.
**Philosophy:**
"The SDK as a Bridge" - This library is the trusted bridge between customer applications and SignNow's API. Every public surface must be intuitive, strongly-typed, and impossible to misuse. Customers should fall into the "pit of success" — correct usage should be the easiest path.
*Metaphor: "The Trusted Courier"* - every SDK call should feel like handing a critical contract to a concierge who takes the direct, recommended route with zero delays or detours.

## 2. Strategic Vision
Deliver a robust, frictionless SDK so developers can add the NuGet package, configure `SignNowContext`, and issue their first API call within minutes. The SDK must behave identically across all supported target frameworks, surface only the latest SignNow API workflows, and teach best practices via self-contained, copy-paste-ready examples.
This SDK serves as the **official .NET integration point** for SignNow's electronic signature platform. Technical implications:

- **Broad Compatibility:** Must compile and run identically across .NET Framework 4.6.2, .NET Standard 2.0/2.1, and modern .NET. No platform-specific APIs without conditional compilation.
- **Zero Friction Integration:** Customers must be able to add the NuGet package, configure `SignNowContext`, and make their first API call within minutes.
- **Copy-Paste Ready Examples:** The `/Examples` project is customer-facing documentation. Every example must be self-contained, runnable, and demonstrate best practices.
- **Single Path Principle:** When SignNow API offers multiple ways to accomplish a task, the SDK exposes only the latest/recommended approach. No legacy API endpoint wrappers.

## 3. Architectural Boundaries
```plaintext
+---------------------------+
| Consumer Apps / Examples |
+-------------+-------------+
|
v
+---------------------------+
| Public SDK Surface |
| (SignNowContext, DTOs) |
+-------------+-------------+
|
v
+---------------------------+
| Domain Services & Models |
| (Service/, _Internal/Model)
+-------------+-------------+
|
v
+---------------------------+
| Infrastructure & Transport|
| (_Internal/Infrastructure)|
+-------------+-------------+
|
v
+---------------------------+
| SignNow REST API |
+---------------------------+
```

### Layer Rules (Access Matrix)
| Layer | CAN Access | CANNOT Access |
|-------|------------|---------------|
| Consumer Apps & `SignNow.Net.Examples` | Public SDK Surface | Domain internals, infrastructure helpers |
| Public SDK Surface (`SignNowContext`, `Interfaces/`, DTOs) | Domain Services & Models | Infrastructure plumbing, HTTP adapters |
| Domain Services & Models (`Service/`, `_Internal/Model`, mappers) | Infrastructure & Transport | Consumer utilities, UI concerns |
| Infrastructure & Transport (`_Internal/Infrastructure`, Helpers, adapters) | SignNow REST API, serialization libraries | Consumer apps, presentation layers |

### Layer Constraints

- **Public API Surface:** All public types must have XML documentation. No breaking changes without major version bump.
- **Service Layer:** Services are stateless. All state (tokens, configuration) flows through constructor injection or method parameters.
- **Infrastructure Layer:** HTTP concerns stay here. Services never see `HttpResponseMessage` or status codes directly.

## 4. Data Flow & Patterns
```plaintext
Caller -> SignNowContext -> IService interface -> Domain Service
-> Request builder / validator -> IHttpContentAdapter -> HTTP pipeline
-> SignNow REST API -> Response translator -> DTO -> Caller
```
- Orchestration stays thin at the surface;
- All rules live in services;
- Transport remains abstract and testable;\
- Serialization/deserialization never leaks into consumer-facing layers.

## 5. Development Constraints
* **Tech Stack Rules:**
- Preserve all existing target frameworks and MSBuild property imports;
- Guard any platform-specific API behind conditional compilation;
- Rely on the provided HttpClient abstractions and Newtonsoft.Json converters;
- Do not introduce new external SaaS dependencies.
* **State Management:**
- Keep `SignNowContext` and services stateless aside from injected tokens;
- Prefer async/await end-to-end with no sync-over-async;
- Cache credentials or documents only through approved adapters;
- Never store mutable state in statics except immutable configuration.
* **Critical Data Constraint:**
- Treat tokens, invites, document payloads, and signer identifiers as sensitive—never log raw values;
- Redact PII in diagnostics;
- Stream large documents to limit memory pressure;
- Normalize and persist timestamps in UTC;
- Respect API-provided idempotency keys when available;
- All API errors surface as `SignNowException` or its derivatives;
- Exception messages must be actionable for customers.
* **Documentation Rules:**
- All public types and members require XML documentation
- Use `<example>` tags for common usage patterns
- Parameter descriptions must explain valid values and constraints

## 6. Anti-Patterns (Forbidden)
- ❌ **YAGNI violations (You Aren't Gonna Need It):** Don't add functionality until it's actually needed.
- No "just in case" features, configurations, or abstractions
- No future-proofing for hypothetical requirements
- No generic solutions when a specific one solves the current problem
- Three similar lines of code is better than premature abstraction
- ❌ **Endpoint Forking:** Never expose multiple SDK paths for deprecated API endpoints; always guide callers through the single, recommended SignNow flow.
- ❌ **Platform Drift:** Introducing APIs unavailable on `net462`/`netstandard2.x` without conditional compilation or fallbacks is prohibited.
- ❌ **Async Blocking & Hidden Threads:** No `.Result`, `.Wait()`, or ad-hoc threads inside SDK services—stay purely async through the supplied HttpClient infrastructure.

## 7. Critical File Locations
```plaintext
.
├─ AGENTS.md
├─ SignNow.Net.sln ← SACRED (DO NOT MODIFY)
├─ Directory.Build.props ← SACRED (DO NOT MODIFY)
├─ SignNow.props ← SACRED (DO NOT MODIFY)
├─ netfx.props ← SACRED (DO NOT MODIFY)
├─ .editorconfig ← SACRED (Coding conventions source of truth)
├─ SignNow.Net/
│ ├─ SignNowContext.cs ← SACRED (Main DI entry point / Composition root)
│ ├─ Interfaces/
│ ├─ Service/
│ ├─ _Internal/
│ │ ├─ Infrastructure/
│ │ └─ Model/
│ └─ Extensions/
├─ SignNow.Net.Examples/
│ ├─ ExamplesBase.cs ← SACRED (DO NOT MODIFY)
│ └─ Scenario folders (customer-facing)
├─ SignNow.Net.Test/
│ ├─ AcceptanceTests/
│ ├─ FeatureTests/
│ └─ UnitTests/
└─ logs/ (diagnostics only)
```

---

Last Updated: 2026-02-03

Maintained by: AI Agents under human supervision
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com)
and this project adheres to [Semantic Versioning](http://semver.org).

## [Unreleased] - TBD
### Added
- Event Subscriptions & Webhooks:
- Get Callbacks History by ID: webhook callback event history related to subscription ID with advanced filtering and sorting capabilities

## [1.4.0] - 2026-01-13
### Added
Expand Down
Loading