Skip to content

frankieyip/QrCheckInSystem

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

QR Check-In System

A .NET 8 ASP.NET Core Web API that records check-in and check-out events triggered when users scan QR codes with their mobile phones.


How It Works

Point A (Check-In)                    Point B (Check-Out)
┌──────────────┐                       ┌──────────────┐
│  QR Code     │                       │  QR Code     │
│ locationId=  │                       │ locationId=  │
│   loc123     │                       │   loc123     │
│ checkType=   │                       │ checkType=   │
│  checkin     │                       │  checkout    │
└──────┬───────┘                       └──────┬───────┘
       │ user scans                            │ user scans
       ▼                                       ▼
┌──────────────────────────────────────────────────────┐
│              Browser  (Mobile Phone)                  │
│                                                       │
│  1. Opens scanner.html?locationId=loc123&             │
│              checkType=checkin                        │
│                                                       │
│  2. Reads UUID from localStorage                      │
│     • If missing or >2 h old → generate new UUID     │
│     • Same phone = same UUID for up to 2 hours       │
│     • Different phone = different UUID                │
│                                                       │
│  3. User taps "Confirm & Submit"                      │
│     POST /api/checkin  { deviceUuid, locationId,      │
│                          checkType, timestamp }       │
└──────────────────────────────────────────────────────┘
       │                                       │
       ▼                                       ▼
┌──────────────────────────────────────────────────────┐
│              ASP.NET Core Web API                     │
│  • Validates payload                                  │
│  • Stamps ServerTimestamp = DateTime.UtcNow           │
│  • Saves to MS SQL via Entity Framework               │
└──────────────────────────────────────────────────────┘
       │
       ▼
┌──────────────────────────────────────────────────────┐
│         MS SQL  –  CheckInRecords table               │
│  Id | DeviceUuid | LocationId | CheckType | …        │
│   1 | a1b2-…     | loc123     | checkin   | …        │
│   2 | a1b2-…     | loc123     | checkout  | …        │
└──────────────────────────────────────────────────────┘

Project Structure

QrCheckInSystem/
├── QrCheckInSystem.sln
├── database_setup.sql               ← Manual SQL alternative to EF migrations
└── QrCheckInSystem.Api/
    ├── Controllers/
    │   ├── CheckInController.cs     ← POST /api/checkin, GET /api/checkin/…
    │   └── QrCodeController.cs      ← GET /api/qrcode (returns PNG)
    ├── Data/
    │   ├── AppDbContext.cs
    │   └── Migrations/
    │       ├── 20240101000000_InitialCreate.cs
    │       └── AppDbContextModelSnapshot.cs
    ├── Models/
    │   ├── CheckInRecord.cs         ← EF entity
    │   └── Dtos.cs                  ← Request/response DTOs
    ├── Services/
    │   └── CheckInService.cs        ← Business logic
    ├── wwwroot/
    │   └── scanner.html             ← Mobile browser scanner page
    ├── Program.cs
    ├── appsettings.json
    └── appsettings.Development.json

Prerequisites

Tool Version
.NET SDK 8.0+
MS SQL Server 2019+
dotnet-ef (CLI) 8.0+

Install the EF CLI tool once:

dotnet tool install --global dotnet-ef

Quick Start

1. Configure the database connection

Edit appsettings.Development.json (or set environment variable):

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost,1433;Database=QrCheckInDb_Dev;User Id=sa;Password=YourStrong@Password;TrustServerCertificate=True;"
  },
  "App": {
    "PublicBaseUrl": "http://localhost:5000"
  }
}

Tip: For Windows Auth use Trusted_Connection=True; instead of User Id/Password.

2. Apply database migrations (auto-runs on startup too)

cd QrCheckInSystem.Api
dotnet ef database update

Or use the manual SQL script:

sqlcmd -S localhost -i ../database_setup.sql

3. Run the API

dotnet run --project QrCheckInSystem.Api

The API starts on http://localhost:5000 (HTTP) and https://localhost:5001 (HTTPS).

4. Generate QR codes

Open in browser or use curl:

# Check-in QR for Point A
GET http://localhost:5000/api/qrcode?locationId=loc123&checkType=checkin

# Check-out QR for Point B
GET http://localhost:5000/api/qrcode?locationId=loc123&checkType=checkout

Print these PNG images and place them at Points A and B.

5. Test manually

curl -X POST http://localhost:5000/api/checkin \
  -H "Content-Type: application/json" \
  -d '{
    "deviceUuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "locationId": "loc123",
    "checkType": "checkin",
    "timestamp": "2024-06-01T09:00:00Z"
  }'

API Reference

POST /api/checkin

Records a check-in or check-out event.

Request body:

{
  "deviceUuid":  "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "locationId":  "loc123",
  "checkType":   "checkin",
  "timestamp":   "2024-06-01T09:00:00Z"
}

Response 201:

{
  "success": true,
  "message": "Successfully recorded checkin for location loc123.",
  "data": {
    "recordId":        1,
    "deviceUuid":      "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "locationId":      "loc123",
    "checkType":       "checkin",
    "serverTimestamp": "2024-06-01T09:00:01.234Z"
  }
}

GET /api/checkin/device/{deviceUuid}

Returns all events for a specific device UUID.


GET /api/checkin/location/{locationId}?from=&to=

Returns all events at a location. Optional UTC datetime filters:

  • from – include records at or after this time
  • to – include records at or before this time

GET /api/qrcode?locationId=&checkType=

Returns a PNG image of the QR code to print. The QR encodes:

https://<host>/scanner?locationId=loc123&checkType=checkin

GET /api/qrcode/url?locationId=&checkType=

Returns the scanner URL as JSON (useful if you want to render the QR client-side).


UUID Lifecycle (Device Identity)

Scenario Behaviour
First visit on Phone A New UUID generated, stored in localStorage, expires in 2 h
Phone A re-scans within 2 h Same UUID returned — check-in and check-out are correlated
Phone A re-scans after 2 h New UUID generated (new logical session)
Phone B scans Different UUID (each device has isolated localStorage)
User clears browser data New UUID on next visit
User opens incognito tab New UUID (incognito storage is isolated)

The key logic lives in scanner.html → getOrCreateDeviceUuid():

const UUID_TTL_MS = 2 * 60 * 60 * 1000; // 2 hours

function getOrCreateDeviceUuid() {
  const stored = localStorage.getItem('qr_device_uuid');
  const expiry = parseInt(localStorage.getItem('qr_device_uuid_expiry') || '0');

  if (stored && expiry && Date.now() < expiry) return stored;  // still valid

  const uuid = crypto.randomUUID();
  localStorage.setItem('qr_device_uuid',        uuid);
  localStorage.setItem('qr_device_uuid_expiry', Date.now() + UUID_TTL_MS);
  return uuid;
}

Swagger UI

Available at: http://localhost:5000/swagger


Production Checklist

  • Set App:PublicBaseUrl to your HTTPS domain so QR codes encode the correct URL
  • Store the connection string in an environment variable or Azure Key Vault
  • Tighten CORS policy in Program.cs to your specific frontend domain
  • Add authentication (API key / JWT) to the /api/checkin endpoint
  • Switch to HTTPS and redirect HTTP → HTTPS
  • Consider rate-limiting per IP to prevent spam
  • Remove db.Database.Migrate() from Program.cs and run migrations as a deploy step

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published