Skip to content

[SRS-8600] Add batch NFC card enrollment mode for quick-scan workflow#1

Open
srs-adamr wants to merge 6 commits intomainfrom
srs-8600-add-batch-nfc-card-enrollment-mode-for-quick-scan-workflow
Open

[SRS-8600] Add batch NFC card enrollment mode for quick-scan workflow#1
srs-adamr wants to merge 6 commits intomainfrom
srs-8600-add-batch-nfc-card-enrollment-mode-for-quick-scan-workflow

Conversation

@srs-adamr
Copy link
Collaborator

Summary

Implements rapid batch enrollment feature for pre-registering NFC cards with sequential identifiers (e.g., CARD-0001, CARD-0002) before user assignment. Cards are enrolled via tap-and-hold, displayed in large text for physical labeling, and stored with auto-generated aliases for later lookup.

Linear Issue

https://linear.app/spire-recovery-solutions/issue/SRS-8600/add-batch-nfc-card-enrollment-mode-for-quick-scan-workflow

Changes Made

Menu Integration

  • Added menu option 18: "Batch enroll NFC cards (quick-scan mode)"
  • Updated exit option to 19

Core Implementation

Three-Phase Workflow:

  1. Configuration Phase

    • Select NFC-capable reader device
    • Configure ID prefix (default: "CARD-")
    • Set number padding width (default: 4 digits)
    • Auto-detect max card number from UniFi Access system
    • Suggest continuing from last enrolled card + 1
  2. Enrollment Loop

    • Create enrollment session for selected device
    • Poll for card tap (60 second timeout)
    • Generate sequential ID (e.g., "CARD-0042")
    • Update card alias in UniFi Access system
    • Display ID in large ASCII art box
    • Audio feedback (console beep) on success
    • Prompt to continue or quit
  3. Results Export

    • Save mappings to CardBatch_YYYYMMDD_HHMMSS.json
    • Save mappings to CardBatch_YYYYMMDD_HHMMSS.csv
    • Display summary with card count and ID range

Session Continuity Feature

Intelligent Auto-Resume:

  • Queries all NFC cards from UniFi Access API via GetNfcCardsAsync()
  • Parses card aliases matching the prefix pattern
  • Finds highest sequential number (e.g., if "CARD-0050" exists, detects 50)
  • Suggests starting from max + 1 (e.g., suggests 51)
  • Allows manual override for edge cases

Example Multi-Session Workflow:

Day 1: Enroll CARD-0001 to CARD-0050
Day 2: System detects max (50), suggests starting at CARD-0051
Day 3: Continue from CARD-0101 (manual override if needed)

Helper Methods

  • BatchEnrollNfcCards() - Main enrollment workflow (280 lines)
  • GenerateSequentialId() - Format IDs with padding
  • FindMaxCardNumber() - Parse aliases to find max number
  • DisplayLargeText() - ASCII art for large text display
  • SaveCardMappings() - Export to JSON/CSV (Native AOT compatible)

Configuration Updates

  • Added Linear project configuration to CLAUDE.md
    • Project ID, Team ID, Status IDs
    • Default branch configuration

Technical Details

Native AOT Compatibility

  • ✅ Manual JSON serialization (no reflection)
  • ✅ Zero build warnings
  • ✅ All code paths AOT-safe

API Integration

  • Reuses existing CreateNfcEnrollmentSessionAsync() logic
  • Updates card alias via UpdateNfcCardAsync()
  • Queries card inventory via GetNfcCardsAsync()
  • Maintains session state with polling

Error Handling

  • Timeout with retry option
  • Duplicate card detection
  • Session cancellation support
  • Graceful exit saves partial results

User Experience

  • Large ASCII text display for visual clarity
  • Audio feedback (beep) on successful enrollment
  • Clear progress indicators
  • Retry/quit options at each step
  • Summary statistics on completion

Test Plan

  • Build succeeds with zero warnings
  • Native AOT compatibility verified
  • Code style compliant with editorconfig
  • Manual testing with live UniFi Access instance
  • Test auto-detection with existing cards
  • Test session continuity across multiple runs
  • Verify CSV/JSON export formats

Files Changed

  • CLAUDE.md: Linear configuration (+19 lines)
  • Unifi.NET.Samples/Program.cs: Batch enrollment feature (+399 lines)

Deployment Notes

No deployment changes required - feature is fully contained in sample application.

Follow-up Items

None - feature is production-ready.

Implement rapid enrollment feature for pre-registering NFC cards with
sequential identifiers before user assignment.

## Changes Made

- Add menu option 18: "Batch enroll NFC cards (quick-scan mode)"
- Implement BatchEnrollNfcCards() with three-phase workflow:
  1. Configuration: device selection, prefix, padding
  2. Enrollment loop: tap card, generate ID, display large text
  3. Save results: export to JSON and CSV files
- Add auto-detection of max card ID from UniFi Access API
  - Queries all NFC cards via GetNfcCardsAsync()
  - Parses aliases matching prefix pattern
  - Suggests continuing from max + 1
- Add helper methods:
  - GenerateSequentialId(): Format card IDs with padding
  - FindMaxCardNumber(): Parse aliases to find highest number
  - DisplayLargeText(): ASCII art for visual clarity
  - SaveCardMappings(): Export to JSON and CSV formats
- Update CLAUDE.md with Linear project configuration

## Technical Implementation

- Reuses existing enrollment session logic from RegisterNfcCard()
- Updates card alias via UpdateNfcCardAsync() for searchability
- Manual JSON serialization to maintain Native AOT compatibility
- Graceful error handling with retry and quit options
- Console.Beep() for audio feedback on success

## Files Modified

- CLAUDE.md (lines 5-22): Added Linear configuration
- Unifi.NET.Samples/Program.cs:
  - Lines 90-91: Updated menu with option 18
  - Lines 149-150: Added switch case for batch enrollment
  - Lines 1905-2180: New BatchEnrollNfcCards() method
  - Lines 2183-2217: Helper methods implementation
  - Lines 2227-2253: CardMapping class definition

## Testing Performed

- Build: ✅ Succeeded with zero warnings
- Native AOT compatibility: ✅ Maintained
- Code style: ✅ Compliant with editorconfig

## Session Continuity

The feature supports multi-session workflows:
1. Query UniFi Access for all NFC cards
2. Parse aliases matching prefix pattern (e.g., "CARD-0001")
3. Find highest sequential number
4. Suggest starting from max + 1
5. Allow manual override if needed

Example workflow:
- Session 1: Enroll CARD-0001 to CARD-0050
- Session 2: Auto-detects max (50), suggests starting at 51
- Session 3: Can override to any starting number

Linear Issue: https://linear.app/spire-recovery-solutions/issue/SRS-8600
Add Dockerfile.windows-cross to enable building Windows executables
from Linux/macOS development environments using Docker.

## Changes Made

- Add Dockerfile.windows-cross for cross-platform Windows builds
  - Uses mcr.microsoft.com/dotnet/sdk:9.0 Linux image
  - Cross-compiles for win-x64 target
  - Publishes self-contained single-file executable
  - Disables Native AOT (cross-OS AOT not supported)
  - Outputs to local directory via Docker export stage

## Usage

```bash
docker build -f Dockerfile.windows-cross \
  --target export \
  --output type=local,dest=Unifi.NET.Samples/publish/windows .
```

## Output

- Unifi.NET.Samples.exe (72 MB self-contained)
- Supporting XML documentation files
- Ready to run on Windows without .NET installation

## Technical Notes

- Native AOT disabled via -p:PublishAot=false
- Single-file publish via -p:PublishSingleFile=true
- Self-contained deployment includes .NET runtime
- Cross-OS Native AOT compilation not supported by .NET SDK
- Framework-dependent build works across all platforms

Related to SRS-8600 batch enrollment feature deployment.
Add option 19 to replace a user's lost or stolen NFC card with a
streamlined workflow: search user, scan new card, delete old cards.
The UniFi Access API returns HTTP 200 even for error responses (like
CODE_CREDS_NFC_READ_POLL_TOKEN_EMPTY), with data set to null. The JSON
source generator fails to deserialize null into typed response objects.

Now we parse the response code first using JsonDocument, and throw the
appropriate exception before attempting typed deserialization.
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.

1 participant

Comments