Skip to content

Rajeev02/VMS

Repository files navigation

Enterprise Visitor Management System (VMS)

React Native Architecture Backend

A production-grade, end-to-end Enterprise Visitor Management System built with React Native (Expo) and Firebase. This application handles the entire visitor lifecycle from pre-registration and host approval to QR-based multi-gate checkpoint verification and strict compliance auditing.

Overview

The Enterprise VMS is designed to replace legacy paper-based logbooks with a secure, digital, and automated workflow. It addresses the security and compliance needs of large corporate campuses by ensuring every entry, internal movement, and exit is cryptographically tied to a dynamic QR pass and immutably recorded.

Demo

VMS guard dashboard active visits demo

View the full demo gallery with screenshots and videos here:


Core Features & Workflows

1. Role-Based Access Control (RBAC) & Personas

The system dynamically limits UI capabilities based on who logs in.

Persona Role Primary Capabilities
Security Guard / Security Officer Point of Entry Scan QR passes, log multi-gate checkpoints, create walk-in visitors, check visitors in/out, and manually verify visitors.
Host (Employee) Internal Employee Pre-approve expected guests, approve/reject walk-in guests, and view only visits related to their own host account.
Receptionist / Admin Admin / Monitor View the live traffic dashboard, register walk-ins, check visitors in/out, and export audit logs.

Extended Documentation

For a deeper dive into the system's inner workings, please refer to our dedicated documentation inside the docs/ folder:

2. Visitor Registration Flows

We support both Host Pre-Approval and Walk-In flows cleanly via the RegisterWalkInVisitorUseCase.

  • Host Pre-Approval Flow: An employee (Host) registers a guest in advance. The system sets the visit to APPROVED and dynamically generates a secure VisitorPass with a time-limited validUntil window. The visitor pass URL is sent through the configured notification channels.
  • Walk-in Flow: A guest arrives without prior notice. Security or Reception creates the visitor profile. The system sets the visit to PENDING and no pass is generated. The Host receives a notification. Once the Host accepts via ProcessApprovalUseCase, the pass is generated.
  • Photo Capture: Visitor and live check-in photos are uploaded to Firebase Storage through IStorageService. Firestore stores the Firebase download URL, not a local device file:// path, so the public web pass can show valid web images. If no valid image exists, the web pass falls back to a placeholder.

3. Web-Based Digital Pass for Visitors

Because external visitors do not download the VMS application, the system generates a secure, web-based digital pass.

  • Once a visit is APPROVED, the system creates a unique cryptographic token and generates a public URL.

  • The pass document stores the same secure value in id, qrToken, and token, and share actions rebuild stale or mock URLs from the real token before sending them through WhatsApp, SMS, email, or native share.

  • This URL is shared with the visitor. They simply tap the link to view their dynamic QR code on their mobile browser.

  • The public pass page lives in the separate GitHub Pages project at /Users/rajeevjoshi/Documents/GitHub/Rajeev02.github.io/public/vms/. Its lookup supports both token and legacy qrToken fields.

  • Live Examples (Ready to Scan): Try clicking these to see how the web app handles each status, or scan them using the mobile app:

    Valid Passes

    1. John Doe's Pass
    2. Jane Smith's Pass

    Invalid / Other States 3. Expired Pass 4. Already Used/Scanned 5. Revoked Pass

    Demo pass records can be refreshed with:

    node seed-passes.js

4. Check-In & Multi-Gate Verification

  • Atomic Check-In: Security scans the pass. ValidateQrScanUseCase ensures the pass exists, is inside its validFrom/validUntil window, and is not EXPIRED, REVOKED, or SCANNED. If valid, Firebase runTransaction securely locks the DB, setting Visit to CHECKED_IN.
  • Checkpoints: Security at restricted areas (e.g., Server Room) scans the pass using VerifyCheckpointUseCase. This logs the location access in checkpoint_logs without checking the user out of the building.
  • Atomic Check-Out: Scanning the pass upon exit permanently sets the Visit to COMPLETED and the VisitorPass to EXPIRED, completely blocking pass reuse.

5. Dashboard Data Scoping

Dashboard data is scoped to the authenticated user:

  • Security Guard, Security Officer, Receptionist, Company Admin, and Super Admin users can see operational visit data across the site.
  • Host and Standard Employee users see only visits where hostId or createdBy matches their authenticated user ID.
  • The dashboard greeting uses the stored user name when available and falls back to email, role, or User.

6. System Audit Logging

Every critical action is logged immutably via IAuditLogService into the system_audit_logs collection to satisfy SOC2/GDPR compliance. Receptionists can export this data as a CSV.


Test Credentials

For manual testing, you can use the following Firebase Auth credentials. These route you to the appropriate UI flows based on the RBAC implementation.

Persona Email (Login) Password
Host host@company.com password123
Security Guard guard@company.com password123
Security Officer officer@company.com password123
Receptionist admin@company.com password123
Seed Host host@vms.com Password123!
Seed Security Guard security@vms.com Password123!
Seed Receptionist receptionist@vms.com Password123!
Seed Company Admin companyadmin@vms.com Password123!
Seed Super Admin superadmin@vms.com Password123!

To create or refresh the @company.com demo users, run:

FIREBASE_WEB_API_KEY=your_firebase_web_api_key node seedCredentials.js

The seeded @vms.com users are part of the Firebase seed data and are useful for validating role-specific dashboards.


Architecture

The project adheres strictly to Clean Architecture principles.

Dependency Injection (Service Locator)

We use a static ServiceLocator to inject external dependencies (IAuditLogService, IStorageService) into our Use Cases. This ensures the Domain is 100% pure and highly testable.

// Example: Use Case Decoupling
this.auditLogger = auditLogger || ServiceLocator.getAuditLogger();

Directory Structure

src/
├── app/                  # Redux store configuration
├── core/                 # Shared utilities, Logger, RBAC, ServiceLocator DI
├── domain/               # Enterprise business rules (Models, Enums, Interfaces)
├── features/             # Feature modules (Use Cases, Screens, Components)
│   ├── auth/             # Login and RBAC State
│   ├── dashboard/        # Role-scoped KPI Dashboard
│   ├── notifications/    # Email/SMS Mock facades
│   ├── qr/               # QR Scanning, Validation, and Checkpoint logic
│   ├── reports/          # CSV Generation and Audit Exports
│   └── visitor/          # Visitor Lifecycle (Approval, Check-In/Out)
├── infrastructure/       # Concrete implementations (Firebase, Mock services)
└── theme/                # Global styling and color tokens

Technology Stack

Category Technology
Framework React Native (Expo)
Language TypeScript
State Management Redux Toolkit
Database Firebase Firestore
Styling React Native Paper / StyleSheet
Camera/Scanner expo-camera
Navigation React Navigation

Prerequisites

  • Node.js (v18+)
  • Expo CLI (npm install -g expo-cli)
  • Firebase Account and configured Project

Installation & Local Setup

1. Repository Setup

Clone the repository and install the required dependencies:

git clone https://github.com/your-org/enterprise-vms.git
cd enterprise-vms
npm install

2. Firebase Configuration (Mandatory)

Because this project uses native Firebase SDKs (@react-native-firebase), you must connect it to a real Firebase project to run it locally.

  1. Go to the Firebase Console and create a new project.
  2. Enable Firestore Database (start in Test Mode for local dev).
  3. Enable Firebase Authentication (Email/Password provider).
  4. Register an Android App and an iOS App in your Firebase project.
  5. Download the google-services.json (for Android) and GoogleService-Info.plist (for iOS).
  6. Place both of these files in the absolute root directory of this repository (/enterprise-vms/).

3. Fresh Clone Secret Setup

Firebase config files and API keys are intentionally not committed to this repository.

After cloning, add these local-only files in the project root:

google-services.json
GoogleService-Info.plist

These files are ignored by git through .gitignore, along with service-account keys:

google-services.json
GoogleService-Info.plist
config/serviceAccountKey.json
keys/

For local utility scripts, pass the Firebase Web API key through an environment variable instead of editing the script:

FIREBASE_WEB_API_KEY=your_firebase_web_api_key node seedCredentials.js
FIREBASE_WEB_API_KEY=your_firebase_web_api_key node verifyUsers.js

If you use a different Firebase project ID, provide it as well:

FIREBASE_PROJECT_ID=your_project_id FIREBASE_WEB_API_KEY=your_firebase_web_api_key node seedCredentials.js

4. Running the Application

Since this project uses native libraries like Vision Camera, you must prebuild the app or use Expo Go if plugins allow. For the best development experience:

# Start the bundler and clear cache
npx expo start --clear

# Run on iOS simulator
npm run ios

# Run on Android emulator
npm run android

Debugging & Troubleshooting

If you run into issues while evaluating or running the project, check these common fixes:

  • App crashes immediately on launch: Double-check that your google-services.json and GoogleService-Info.plist files are correctly placed in the root directory. Firebase native will crash if these are missing.
  • "Firestore permission denied": Ensure your Firestore Security Rules in the Firebase console are set to allow reads/writes (Test Mode).
  • "The query requires an index" ([firestore/failed-precondition]): Firestore requires composite indexes when querying multiple fields (e.g., status and updatedAt). The error in your terminal will provide a direct URL (e.g., https://console.firebase.google.com/v1/r/project/...). Simply click that exact link; it will open your Firebase console and automatically build the required index for you (it takes about 2-3 minutes to build).
  • Metro Bundler Cache Issues: If you get bizarre TypeScript or module resolution errors, clear the Metro cache by running: npx expo start -c.
  • Vision Camera not working in Simulator: The iOS simulator does not support hardware cameras. To test QR scanning, you must run the app on a physical device using npx expo run:ios --device.

Security

  • Transaction Safety: Database writes for Check-In and Check-Out are locked via Firestore native transactions, preventing race conditions like double check-ins.
  • QR Security: QR codes contain secure random tokens, not plain-text user data. Passes are strictly validated against validFrom and validUntil timestamps and rejected for invalid states such as EXPIRED, REVOKED, and SCANNED.
  • Public Pass Images: Public browser passes only render HTTP/HTTPS image URLs. Invalid local device paths fall back to a placeholder image.
  • Firebase Config Hygiene: Real google-services.json, GoogleService-Info.plist, service-account keys, and API keys must stay local and must not be committed. Use environment variables such as FIREBASE_WEB_API_KEY for local scripts.
  • GitGuardian Remediation: A Google API key was previously committed in Firebase config/script files. The current repository removes those tracked config files, moves script API keys to environment variables, and ignores local Firebase config files. Because the key existed in git history, it should still be rotated or restricted in Google Cloud/Firebase Console.
  • Audit Trail: The IAuditLogService captures the userId of the security guard/receptionist performing any mutating action, ensuring non-repudiation.

Future Enhancements & Roadmap

The Enterprise VMS is built on a highly extensible foundation. Here are several feature flows that can be implemented next:

  1. Facial Recognition Check-in: Integrate a third-party SDK (like AWS Rekognition or Azure Face) to allow VIP visitors to check-in via face scan instead of a QR code.
  2. Push Notifications (FCM/APNs): Replace the current MockNotificationServices with actual Firebase Cloud Messaging to send real-time push alerts to Hosts when their guests arrive.
  3. Hardware Integration (Turnstiles/Printers): Connect the VMS to physical turnstiles via Bluetooth/Wi-Fi APIs, or integrate with badge printers (e.g., Brother QL series) to automatically print sticky badges upon check-in.
  4. Self-Service Kiosk Mode: Create a locked-down iPad/Android tablet view where walk-in visitors can register themselves, take their own photo, and automatically ping the Host for approval.
  5. Advanced Analytics Dashboard: Add charts and graphs (using libraries like react-native-chart-kit) to the Receptionist dashboard to visualize peak visitor hours and checkpoint bottlenecks.

Migrating Away From Firebase (Custom Backend)

Because this project strictly adheres to Clean Architecture, replacing Firebase with your own custom backend (e.g., Node.js/Express, Spring Boot, or Go) is incredibly straightforward and requires zero changes to the UI or Use Cases.

Migration Steps:

  1. Create New Data Sources: Inside src/infrastructure/, create new files implementing the Domain interfaces. For example, create RestApiVisitDataSource.ts that implements IVisitDataSource using Axios/Fetch instead of Firestore.

  2. Implement API Calls:

    // Example of RestApiVisitDataSource.ts
    export class RestApiVisitDataSource implements IVisitDataSource {
      async updateVisit(id: string, updates: Partial<Visit>): Promise<Visit> {
        const response = await axios.patch(`https://api.yourcompany.com/visits/${id}`, updates);
        return response.data;
      }
      // ... implement other interface methods
    }
  3. Update the Service Locator: Open src/core/di/ServiceLocator.ts and swap out the Firebase implementations for your new REST implementations.

    // Change this:
    // this.auditLogger = new FirestoreAuditLogService();
    
    // To this:
    this.auditLogger = new RestApiAuditLogService();
  4. Migrate Auth & Storage: Similarly, swap out Firebase Auth with JWT/OAuth logic in your Redux slices, and replace Firebase Storage with your own S3/Blob storage uploads in IStorageService.

Because the entire Domain and Use Case layer only speaks to the interfaces (like IVisitDataSource), the rest of the application will seamlessly switch to your custom backend without breaking a single business rule!

About

Enterprise Visitor Management System built with React Native Expo and Firebase, featuring QR visitor passes, role-based dashboards, approvals, check-in/out, and audit workflows.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors