QR Code-Based Checkpoint Access Management System
Project description
QR In/Out - QR Code-Based Checkpoint Access Management System
한국어 문서 | English
| Admin Dashboard | Host QR Display | Guest Check-In |
Overview
QR In/Out is a comprehensive QR code-based checkpoint access management system built with Python and Streamlit. It enables organizations to deploy static or dynamic QR codes at designated checkpoints, allowing authorized visitors to check in and out by scanning codes via their mobile devices.
Key Features
-
Three Role-Based Pages
- Admin: Manage checkpoints, guests, view activity logs, and configure system settings
- Host: Display QR codes (static or dynamic) at checkpoint locations
- Guest: Scan QR codes to check in/out, view personal visit history
-
Dual QR Code Modes
- Static QR: Never expires, suitable for printable signage
- Dynamic QR: Auto-refreshes every 30 minutes with HMAC-SHA256 signatures for enhanced security
-
Time-Based Access Control
- Checkpoint-specific allowed hours
- Guest-specific allowed hours (optional)
- Timezone-aware validation using World Time API
- Overnight shift support (e.g., 22:00 - 06:00)
-
Security Features
- bcrypt password hashing for admin and checkpoint access
- HMAC-SHA256 signatures for dynamic QR codes
- Sequence number validation to prevent replay attacks
- Time synchronization via World Time API to prevent local time manipulation
- Soft delete mechanism to preserve data history
-
Enhanced User Experience (v1.2)
- WiFi Info Display: Show network SSID/password on Host screen for guest convenience
- Connection Status Monitoring: Real-time server and time API status with visual indicators
- Sound Feedback: Audio confirmation for successful/failed scans (Web Audio API)
- Remember Me: Save guest credentials locally via browser localStorage
- Kiosk Mode: Continuous scanning mode for shared devices at checkpoints
- High Contrast QR: Multiple display modes (default, high contrast, inverted) for various lighting conditions
-
Local Data Storage
- JSON-based storage (no external database required)
- Thread-safe concurrent access
- Offline operation capability
- Activity log persistence
Screenshots
Click to view all screenshots
Home
Admin
| Admin Login | Checkpoint Management |
|---|---|
| Guest Management | Activity Logs |
|---|---|
| Statistics Dashboard |
|---|
Host
| Host Login | QR Code Display |
|---|---|
Guest
| Guest Login | QR Scan |
|---|---|
| Visit History |
|---|
Technology Stack
- Framework: Streamlit (Python web framework)
- QR Generation: qrcode, Pillow
- QR Scanning: pyzbar (requires zbar system library)
- Time Synchronization: World Time API, TimeAPI.io
- Authentication: bcrypt password hashing with salt
- Data Storage: JSON files with thread-safe locks
- Timezone Handling: pytz
- Environment Management: python-dotenv
Installation
Option A: Install via pip (Recommended)
pip install qr-in-out
Option B: Install from source
git clone https://github.com/jakeleekr13-otter/qr_in_out.git
cd qr_in_out
pip install -r requirements.txt
System Dependencies (QR Scanning)
The pyzbar library requires the zbar shared library:
macOS (Homebrew):
brew install zbar
Ubuntu / Debian:
sudo apt-get install libzbar0
Windows:
Usually pip install pyzbar includes necessary DLLs. If issues occur, install Visual C++ Redistributable Packages.
Environment Setup
cp .env.example .env
# Edit .env and set QR_SECRET_KEY (min 32 characters)
# Generate a key: python -c "import secrets; print(secrets.token_hex(32))"
Run
streamlit run app.py
The application will open at http://localhost:8501
Quick Start Guide
Step 1: Admin Setup
- Navigate to 👤 Admin page
- First-time login uses default credentials (you'll be prompted to change password):
- Username:
admin - Password:
admin
- Username:
- IMPORTANT: Change the default password immediately
Step 2: Create Checkpoint
- In Admin page, go to Create Checkpoint section
- Fill in checkpoint details:
- Name (e.g., "Main Entrance")
- Location (e.g., "Building A, 1F")
- Allowed Hours (e.g., 09:00 - 18:00)
- QR Mode: Static (printable) or Dynamic (auto-refresh)
- Admin Password (for Host page access)
- Select which guests are allowed to access this checkpoint
- Click Create Checkpoint
Step 3: Register Guests
- Go to Guest Management section
- Click Register New Guest
- Enter guest information:
- Name (required)
- Email (required)
- Phone (optional)
- Timezone (e.g., Asia/Seoul)
- Allowed Checkpoints
- Custom Allowed Hours (optional)
- Click Register Guest
Step 4: Display QR Code (Host)
- Navigate to 🖥️ Host page
- Select a checkpoint from dropdown
- Enter checkpoint's admin password
- QR code will be displayed:
- Static QR: Download and print for permanent display
- Dynamic QR: Keep browser open; refreshes automatically every 30 minutes
Step 5: Guest Check-In/Out
- Navigate to 👋 Guest page
- Enter Name and Email to authenticate
- Choose action: Check In or Check Out
- Scan QR code using:
- Camera (mobile devices)
- Upload QR Image (screenshot or file)
- System validates and logs activity
- View personal visit history in My Visit History section
New Features in v1.2
WiFi Information Display (Host)
When creating a checkpoint, optionally configure WiFi credentials. The Host page will display these for guest convenience:
- WiFi SSID: Network name guests should connect to
- WiFi Password: Network password
This is particularly useful when guests need to join a specific network to access the QR scanning page.
Connection Status Monitoring
Both Host and Guest pages now display real-time connection status:
| Status | Icon | Description |
|---|---|---|
| All Connected | ✅ | Server and Time API both reachable |
| Partial | ⚠️ | Server connected, Time API unreachable (using local time) |
| Disconnected | ❌ | Cannot reach server |
Sound Feedback (Guest)
Audio feedback plays automatically on scan results:
- Success: Confirmation sound on successful check-in/out
- Error: Alert sound on failed scan
Uses Web Audio API with HTML5 Audio fallback for broad browser support.
Remember Me (Guest)
Enable "Remember Me" on the Guest login page to save credentials locally:
- Uses browser localStorage (never sent to server)
- Persists across sessions
- Clear with "Forget Me" button
Kiosk Mode (Guest)
For shared devices at checkpoint locations:
- Enable "Kiosk Mode" checkbox after login
- Continuous scanning without re-authentication
- 5-minute timeout for security
- No access to personal visit history
High Contrast QR Display (Host)
Choose QR display mode based on environment:
| Mode | Fill Color | Background | Best For |
|---|---|---|---|
| Default | Black | White | Standard lighting |
| High Contrast | Black | Yellow | Bright environments |
| Inverted | White | Black | Dark environments |
Size options: Small (8), Medium (12), Large (16), X-Large (20)
Usage Examples
Scenario 1: Office Building Access
Setup:
- Create checkpoint: "Main Entrance"
- Allowed hours: 08:00 - 20:00
- QR mode: Dynamic (security)
- Register employees as guests
Daily Use:
- Host displays dynamic QR code on monitor at entrance
- Employees scan QR code to check in when arriving (08:30)
- Employees scan again to check out when leaving (18:15)
- Admin monitors real-time activity logs
Scenario 2: Event Registration
Setup:
- Create checkpoint: "Conference Registration Desk"
- Allowed hours: 09:00 - 18:00
- QR mode: Static (printable)
- Register event attendees as guests
Event Day:
- Print static QR code and place at registration desk
- Attendees scan QR code upon arrival
- Staff monitors check-in status via Admin dashboard
- Export activity logs to CSV for attendance records
Scenario 3: Multi-Site Facility Management
Setup:
- Create checkpoints for each building (A, B, C, D)
- Different allowed hours per building
- Assign specific guests to specific buildings
- Guest-level time restrictions for contractors
Operations:
- Each building displays its own QR code (static or dynamic)
- Guests can only access authorized buildings
- Contractor access automatically restricted to assigned hours
- Activity logs track all cross-building movements
System Architecture
qr_in_out/
├── app.py # Main Streamlit entry point
├── pages/
│ ├── 1_👤_Admin.py # Admin management interface
│ ├── 2_🖥️_Host.py # QR code display page
│ └── 3_👋_Guest.py # Guest check-in/out page
├── core/
│ ├── models.py # Data models (Checkpoint, Guest, ActivityLog)
│ ├── storage.py # JSON storage with thread-safe operations
│ ├── auth.py # Authentication and password hashing
│ ├── qr_manager.py # QR generation, validation, signatures
│ ├── time_service.py # Time synchronization via World Time API
│ ├── time_validator.py # Time-based access control validation
│ └── connection_health.py # Connection status monitoring (v1.2)
├── utils/
│ └── helpers.py # Utility functions (email validation, lookups)
├── data/ # JSON storage files (auto-created)
│ ├── checkpoints.json
│ ├── guests.json
│ ├── activity_logs.json
│ └── admin_settings.json
├── assets/
│ └── sounds/ # Audio feedback files (v1.2)
│ ├── success.mp3
│ └── error.mp3
├── docs/ # Documentation and planning artifacts
│ └── planning-artifacts/
│ ├── PRD-Overview.md
│ ├── PRD-Admin.md
│ ├── PRD-Host.md
│ └── PRD-Guest.md
├── requirements.txt # Python dependencies
└── README.md # This file
Network Architecture
QR In/Out supports various network deployment scenarios depending on your organization's needs.
Deployment Scenarios
Scenario 1: LAN (Same Network)
All devices on the same local network
[Streamlit Server: 192.168.1.100:8501]
│
[Local Router]
┌────┴────┐
│ │
[Host] [Guest Mobile]
- Use Case: Single office, event venue
- Setup: All devices connect to the same WiFi
- Guest Access:
http://192.168.1.100:8501
Scenario 2: Cloud Deployment
Server accessible from anywhere
[Internet]
│
[Cloud Server with Public IP]
│
[Reverse Proxy (nginx/Caddy)]
│
[Streamlit: localhost:8501]
- Use Case: Multi-site facilities, remote checkpoints
- Setup: Deploy to cloud provider (AWS, GCP, Azure, etc.)
- Guest Access:
https://yourdomain.com
Scenario 3: VPN/Remote Access
Secure remote access for distributed locations
[HQ Network]─────────[VPN Server]─────────[Remote Office Network]
│ │
[Streamlit Server] [Host Device + Guests]
192.168.1.100:8501 (VPN Clients)
- Use Case: Corporate networks, high-security environments
- Setup: Connect remote sites via VPN tunnel
- Guest Access: After VPN connection,
http://192.168.1.100:8501(internal IP)
Note: In this scenario, guests also need VPN client access. For external visitors (no VPN), use Scenario 2 (Cloud Deployment) instead.
Firewall Configuration
| Port | Protocol | Direction | Description |
|---|---|---|---|
| 8501 | TCP | Inbound | Streamlit default port |
| 443 | TCP | Outbound | World Time API (HTTPS) |
| 80 | TCP | Outbound | World Time API (HTTP fallback) |
| 53 | UDP/TCP | Outbound | DNS (domain name resolution) |
HTTPS Configuration
For production deployments, we recommend using HTTPS:
Option 1: Reverse Proxy (Recommended)
# nginx configuration
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:8501;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Option 2: Streamlit Built-in SSL
streamlit run app.py --server.sslCertFile=cert.pem --server.sslKeyFile=key.pem
Security Considerations
Current Security Measures
- Password hashing for admin and checkpoint access
- HMAC-SHA256 signatures on dynamic QR codes
- Sequence number validation to prevent replay attacks
- Time synchronization to prevent local time manipulation
- Soft delete mechanism (data preservation)
- Thread-safe concurrent storage access
⚠️ Security Warnings
BEFORE PRODUCTION DEPLOYMENT:
✅ Fixed in v1.0: Password hashing upgraded to bcrypt ✅ Fixed in v1.0: SECRET_KEY moved to environment variable ✅ Fixed in v1.0: Deleted guest authentication bypass patched
Still Required:
-
Environment Configuration: Set
QR_SECRET_KEYin.envfile:# Copy .env.example to .env and set your secret key cp .env.example .env # Edit .env and set QR_SECRET_KEY to a secure random value
-
Default Credentials: Change default admin password on first login (prompted automatically)
-
HTTPS: Deploy with HTTPS in production (Streamlit supports via reverse proxy)
-
Data Encryption: Consider encrypting sensitive data at rest for highly sensitive deployments
-
File Permissions: Ensure
data/directory has restricted permissions (0700)
See SECURITY.md for detailed security analysis and additional recommendations.
Configuration
System Settings (Admin Page)
- Admin Timezone: Default timezone for admin operations
- Default Guest Timezone: Default timezone for new guests
- QR Refresh Interval: Dynamic QR refresh period (default: 1800 seconds / 30 minutes)
- Require Time Sync: Enforce time synchronization via World Time API
Environment Variables
Create .env file (not committed to git):
QR_SECRET_KEY=your-secure-random-key-here-min-32-chars
STREAMLIT_SERVER_PORT=8501
Data Models
Checkpoint
{
"id": "uuid",
"name": "Main Entrance",
"location": "Building A, 1F",
"allowed_hours": {"start_time": "09:00", "end_time": "18:00"},
"qr_mode": "static" | "dynamic",
"admin_password_hash": "hashed_password",
"allowed_guests": ["guest_id_1", "guest_id_2"],
"current_qr_sequence": 0,
"wifi_ssid": "Office-Guest-WiFi", # (v1.2) WiFi network name for Host display
"wifi_password": "guest1234", # (v1.2) WiFi password for Host display
"deleted_at": null,
"created_at": "2026-02-05T10:00:00Z",
"updated_at": "2026-02-05T10:00:00Z"
}
Guest
{
"id": "uuid",
"name": "John Doe",
"email": "john@example.com",
"phone": "+1-555-0100",
"timezone": "America/New_York",
"allowed_checkpoints": ["checkpoint_id_1"],
"allowed_hours": {"start_time": "08:00", "end_time": "20:00"},
"deleted_at": null,
"created_at": "2026-02-05T10:00:00Z",
"updated_at": "2026-02-05T10:00:00Z"
}
Activity Log
{
"id": "uuid",
"timestamp": "2026-02-05T14:30:00Z",
"checkpoint_id": "checkpoint_uuid",
"guest_id": "guest_uuid",
"action": "check_in" | "check_out",
"qr_code_used": "{...qr_content...}",
"status": "success" | "failure",
"failure_reason": null | "error message",
"metadata": {"scanned_at": "2026-02-05T14:30:00Z"}
}
API Reference
Core Modules
TimeService
TimeService.get_current_time(timezone_str: str) -> Tuple[datetime, bool]
# Returns: (current_time, is_synchronized)
# Sources: World Time API → TimeAPI.io → Local system time
QRManager
QRManager.generate_static_qr_content(checkpoint_id: str) -> str
QRManager.generate_dynamic_qr_content(checkpoint_id, sequence, issued_at, expires_at) -> str
QRManager.verify_signature(qr_content: Dict) -> bool
QRManager.is_qr_expired(qr_content: Dict, current_time: datetime) -> bool
AuthManager
AuthManager.hash_password(password: str) -> str
AuthManager.verify_password(password: str, password_hash: str) -> bool
Troubleshooting
Common Issues
1. "pyzbar library is not available" Error
Cause: zbar system library not installed
Solution: Install system dependency:
# macOS
brew install zbar
# Ubuntu/Debian
sudo apt-get install libzbar0
2. Time Synchronization Failures
Symptoms: "Not Synchronized (Using Server Time)" warning
Causes:
- No internet connection
- World Time API unavailable
- Firewall blocking API requests
Solution:
- Check internet connection
- Verify firewall allows HTTP/HTTPS to
worldtimeapi.organdtimeapi.io - System will fall back to local time with warning
3. QR Code Scan Fails with "Invalid Signature"
Cause: SECRET_KEY mismatch or QR code tampering
Solution:
- Ensure SECRET_KEY is consistent across all components
- Regenerate QR code from Host page
- Do not manually edit QR code content
4. Guest Cannot Authenticate
Causes:
- Email/name mismatch (check case sensitivity)
- Guest deleted (soft delete)
- Typos in email or name
Solution:
- Verify exact spelling of name and email
- Check Admin page to confirm guest is active (not deleted)
- Email is case-insensitive but must match exactly
5. Access Denied During Allowed Hours
Causes:
- Checkpoint allowed hours restriction
- Guest-specific allowed hours restriction
- Timezone mismatch
Solution:
- Check both checkpoint AND guest allowed hours
- Verify guest's timezone setting matches their actual location
- Ensure current time is within BOTH time windows
Contributing
We welcome contributions! Please follow these guidelines:
- Fork the repository
- Create a branch for your feature (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Setup
# Clone your fork
git clone https://github.com/jakeleekr13-otter/qr_in_out.git
cd qr-in-out
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Run tests (when available)
pytest
# Run application
streamlit run app.py
Code Style
- Follow PEP 8 guidelines
- Use type hints where applicable
- Add docstrings to all public functions
- Write unit tests for new features
Roadmap
Planned Features
- Enhanced Security: bcrypt password hashing (completed in v1.0)
- Network Architecture Documentation: Deployment guides and firewall settings (completed in v1.2)
- WiFi Info Display: Show network credentials on Host screen (completed in v1.2)
- Connection Status Monitoring: Real-time server and API status (completed in v1.2)
- Sound Feedback: Audio confirmation for scan results (completed in v1.2)
- Remember Me: Save guest credentials locally (completed in v1.2)
- Kiosk Mode: Continuous scanning for shared devices (completed in v1.2)
- High Contrast QR: Multiple display modes for accessibility (completed in v1.2)
- Multi-Language Support: Internationalization (i18n)
- Database Backend: PostgreSQL/MySQL option for larger deployments
- Email Notifications: Alert guests on check-in/out
- Mobile App: Native iOS/Android companion app
- API Endpoints: REST API for third-party integrations
- Analytics Dashboard: Advanced reporting and visualizations
- Role-Based Access Control: Granular permissions for admin users
- Audit Logs: Comprehensive admin action logging
- Backup/Restore: Automated data backup functionality
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
- Built with Streamlit
- QR code generation powered by qrcode
- QR code scanning powered by pyzbar
- Time synchronization via World Time API and TimeAPI.io
- Timezone handling by pytz
Support
- Documentation: docs/
- Issues: GitHub Issues
- Discussions: GitHub Discussions
💖 Support
If you find this tool useful, please consider supporting development!
- ⭐ Star this repo: It helps a lot!
- 💖 Sponsor me on GitHub: https://github.com/sponsors/jakeleekr13-otter
- ☕ Buy Me a Coffee: https://buymeacoffee.com/jakeleekr13otter
Your support helps improve and maintain this project.
Disclaimer
This software is provided "as-is" without warranty. Please review security considerations before deploying in production environments. The default configuration is intended for development and testing purposes.
Made with ❤️ using Python and Streamlit
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file qr_in_out-1.0.3.tar.gz.
File metadata
- Download URL: qr_in_out-1.0.3.tar.gz
- Upload date:
- Size: 41.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
707151414f3e2358d01b2c4cdf1ecb0cd7776728303012523f347daa2a815e56
|
|
| MD5 |
4937afafe0cdef3783325f8eb1fcdc6e
|
|
| BLAKE2b-256 |
212157468d809e3a40623d1a1f6b8ba0b517eb67b55dd9e7a2cfae05365ecbc5
|
Provenance
The following attestation bundles were made for qr_in_out-1.0.3.tar.gz:
Publisher:
publish.yml on jakeleekr13-otter/qr_in_out
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qr_in_out-1.0.3.tar.gz -
Subject digest:
707151414f3e2358d01b2c4cdf1ecb0cd7776728303012523f347daa2a815e56 - Sigstore transparency entry: 929151301
- Sigstore integration time:
-
Permalink:
jakeleekr13-otter/qr_in_out@170595151ec1d019e13720c5002b49f5857aaeb6 -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/jakeleekr13-otter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@170595151ec1d019e13720c5002b49f5857aaeb6 -
Trigger Event:
release
-
Statement type:
File details
Details for the file qr_in_out-1.0.3-py3-none-any.whl.
File metadata
- Download URL: qr_in_out-1.0.3-py3-none-any.whl
- Upload date:
- Size: 36.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
00289bd2b4b9ec2ced7d88a273b9cbe69e2771531c1c2d97cc3ab84ecb78336b
|
|
| MD5 |
ee8d3bbd855022cd7366b79764e0f2af
|
|
| BLAKE2b-256 |
8b2d3099303c42e1e6f91c4f77f207f15047a78095e2f9785b0aefd343a34b21
|
Provenance
The following attestation bundles were made for qr_in_out-1.0.3-py3-none-any.whl:
Publisher:
publish.yml on jakeleekr13-otter/qr_in_out
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
qr_in_out-1.0.3-py3-none-any.whl -
Subject digest:
00289bd2b4b9ec2ced7d88a273b9cbe69e2771531c1c2d97cc3ab84ecb78336b - Sigstore transparency entry: 929151312
- Sigstore integration time:
-
Permalink:
jakeleekr13-otter/qr_in_out@170595151ec1d019e13720c5002b49f5857aaeb6 -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/jakeleekr13-otter
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@170595151ec1d019e13720c5002b49f5857aaeb6 -
Trigger Event:
release
-
Statement type: