240 lines
7.0 KiB
Markdown
240 lines
7.0 KiB
Markdown
# 3D Virtual Tour Map - Architecture Diagram
|
|
|
|
## Technology Stack
|
|
|
|
### Backend
|
|
- **Runtime**: Node.js
|
|
- **Framework**: Express.js
|
|
- **Database**: MongoDB (Mongoose ODM)
|
|
- **Authentication**: JWT (jsonwebtoken) + bcrypt
|
|
- **Image Processing**: Sharp (resize), exifr (read EXIF), piexifjs (write EXIF)
|
|
- **File Upload**: Multer
|
|
- **Security**: CORS, referer verification, no-cache headers
|
|
|
|
### Frontend
|
|
- **Map**: Leaflet.js (OpenStreetMap tiles)
|
|
- **3D Viewer**: Pannellum.js (360° panorama viewer)
|
|
- **UI**: Vanilla HTML/CSS/JavaScript
|
|
- **State**: localStorage for JWT tokens
|
|
|
|
## Architecture Diagram
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Client (Browser)"
|
|
UI[HTML/CSS UI]
|
|
MAP[Leaflet Map]
|
|
VIEWER[Pannellum 3D Viewer]
|
|
AUTH[Auth Panel]
|
|
MODAL[Scene Creation Modal]
|
|
end
|
|
|
|
subgraph "Backend (Node.js/Express)"
|
|
SERVER[server.js]
|
|
ROUTES[API Routes]
|
|
MIDDLEWARES[Security & Auth Middlewares]
|
|
UTILS[Image & EXIF Utils]
|
|
MODELS[Mongoose Models]
|
|
end
|
|
|
|
subgraph "Database (MongoDB)"
|
|
USERS[Users Collection]
|
|
SCENES[Scenes Collection]
|
|
ASSETS[Assets Collection]
|
|
end
|
|
|
|
subgraph "File System"
|
|
UPLOADS[uploads/ Directory]
|
|
TEMP[temp/ Directory]
|
|
end
|
|
|
|
UI --> MAP
|
|
UI --> AUTH
|
|
UI --> MODAL
|
|
UI --> VIEWER
|
|
|
|
MAP -->|Right-click| MODAL
|
|
MAP -->|Load Scenes| ROUTES
|
|
MAP -->|Click Marker| VIEWER
|
|
|
|
AUTH -->|Login/Register| ROUTES
|
|
AUTH -->|Store JWT| UI
|
|
|
|
MODAL -->|Upload Image| ROUTES
|
|
|
|
VIEWER -->|Request Image| ROUTES
|
|
|
|
ROUTES --> MIDDLEWARES
|
|
MIDDLEWARES -->|Verify JWT| AUTH
|
|
MIDDLEWARES -->|Verify Referer| UI
|
|
MIDDLEWARES -->|Privacy Check| SCENES
|
|
|
|
ROUTES --> MODELS
|
|
MODELS --> USERS
|
|
MODELS --> SCENES
|
|
MODELS --> ASSETS
|
|
|
|
ROUTES --> UTILS
|
|
UTILS -->|Resize| UPLOADS
|
|
UTILS -->|Read/Write EXIF| UPLOADS
|
|
UTILS -->|Temp Storage| TEMP
|
|
|
|
SCENES --> ASSETS
|
|
ASSETS --> UPLOADS
|
|
|
|
SERVER --> ROUTES
|
|
SERVER -->|Serve Static| UI
|
|
```
|
|
|
|
## Data Flow
|
|
|
|
### 1. User Registration/Login
|
|
```
|
|
Client → POST /api/auth/register or /api/auth/login
|
|
→ authRoutes.js
|
|
→ User model (bcrypt hash/compare)
|
|
→ JWT generation
|
|
→ Response with token
|
|
→ Client stores token in localStorage
|
|
```
|
|
|
|
### 2. Scene Creation (Upload 360° Image)
|
|
```
|
|
Client → Right-click on map → Open modal with lat/lng
|
|
→ POST /api/scenes (with multipart/form-data)
|
|
→ authMiddleware.protect (verify JWT)
|
|
→ Multer saves to temp/
|
|
→ imageHelper.resizeTo8K (resize to 8192x4096)
|
|
→ exifHelper.getGPSCoordinates (read original GPS)
|
|
→ exifHelper.injectGPSCoordinates (inject map lat/lng)
|
|
→ Asset model saved to DB
|
|
→ Scene model saved to DB (with privacy settings)
|
|
→ Delete temp file
|
|
→ Response with scene data
|
|
```
|
|
|
|
### 3. Load Scenes on Map
|
|
```
|
|
Client → GET /api/scenes (with optional JWT)
|
|
→ authMiddleware.optionalAuth
|
|
→ Scene.find() with privacy filter:
|
|
- Guests: public + shared scenes
|
|
- Logged-in: public + member + owned + shared-with-me
|
|
→ Populate owner and asset data
|
|
→ Response with scene list
|
|
→ Client adds markers to Leaflet map
|
|
```
|
|
|
|
### 4. View 3D Panorama
|
|
```
|
|
Client → Click marker → GET /api/scenes/:id (with token if shared)
|
|
→ authMiddleware.optionalAuth
|
|
→ Privacy verification
|
|
→ Response with scene details
|
|
→ Client constructs secure image URL: /api/assets/view/:assetId?token=...
|
|
→ GET /api/assets/view/:assetId
|
|
→ securityMiddleware.verifyReferer (anti-hotlinking)
|
|
→ securityMiddleware.setNoCacheHeaders
|
|
→ Privacy verification again
|
|
→ Stream image file from disk
|
|
→ Pannellum viewer displays 360° panorama
|
|
→ Client-side security: block right-click, drag, keyboard shortcuts
|
|
```
|
|
|
|
## Security Layers
|
|
|
|
### Backend Security
|
|
1. **JWT Authentication**: Required for creating scenes, optional for viewing
|
|
2. **Privacy Model**: Four levels (public, private, member, shared)
|
|
3. **Referer Verification**: Prevents direct URL access to images
|
|
4. **No-Cache Headers**: Prevents browser caching of protected images
|
|
5. **Share Tokens**: For shared scenes, token required for access
|
|
|
|
### Frontend Security
|
|
1. **Right-click Blocking**: Prevents image saving in viewer
|
|
2. **Drag Prevention**: Blocks drag-and-drop of images
|
|
3. **Keyboard Restrictions**: Blocks F12, Ctrl+S, Ctrl+U, Ctrl+Shift+I
|
|
4. **Token-based Access**: Share tokens passed in URLs for shared content
|
|
|
|
## Database Schema
|
|
|
|
### User Model
|
|
```javascript
|
|
{
|
|
username: String (unique, required),
|
|
password: String (bcrypt hashed),
|
|
role: Enum ['Chủ sở hữu', 'Thành viên'],
|
|
timestamps: true
|
|
}
|
|
```
|
|
|
|
### Scene Model
|
|
```javascript
|
|
{
|
|
title: String (required),
|
|
assetId: ObjectId (ref: Asset),
|
|
lat: Number (required),
|
|
lng: Number (required),
|
|
owner: ObjectId (ref: User),
|
|
privacy: Enum ['public', 'private', 'shared', 'member'],
|
|
shareToken: String (unique, sparse),
|
|
sharedWith: [ObjectId] (ref: User),
|
|
timestamps: true
|
|
}
|
|
```
|
|
|
|
### Asset Model
|
|
```javascript
|
|
{
|
|
filePath: String (required),
|
|
uploadedBy: ObjectId (ref: User),
|
|
coordinates: { lat: Number, lng: Number },
|
|
timestamps: true
|
|
}
|
|
```
|
|
|
|
## File Structure
|
|
|
|
```
|
|
3dtours/
|
|
├── backend/
|
|
│ ├── config/
|
|
│ │ └── db.js # MongoDB connection
|
|
│ ├── middlewares/
|
|
│ │ ├── authMiddleware.js # JWT verification
|
|
│ │ └── securityMiddleware.js # Referer check, cache control
|
|
│ ├── models/
|
|
│ │ ├── User.js # User schema
|
|
│ │ ├── Scene.js # Scene schema
|
|
│ │ └── Asset.js # Asset schema
|
|
│ ├── routes/
|
|
│ │ ├── authRoutes.js # Login/register endpoints
|
|
│ │ └── apiRoutes.js # Scenes/assets endpoints
|
|
│ ├── utils/
|
|
│ │ ├── imageHelper.js # Sharp resize to 8K
|
|
│ │ └── exifHelper.js # GPS read/write
|
|
│ ├── uploads/ # Processed images
|
|
│ │ └── temp/ # Temporary upload storage
|
|
│ ├── server.js # Express app entry point
|
|
│ ├── package.json
|
|
│ └── .env # Environment variables
|
|
└── frontend/
|
|
├── css/
|
|
│ └── style.css # UI styling
|
|
├── js/
|
|
│ ├── main_map.js # Map logic, auth, scene loading
|
|
│ └── viewer360.js # Pannellum viewer + security
|
|
└── index.html # Main UI
|
|
```
|
|
|
|
## Key Features
|
|
|
|
1. **Interactive Map**: Leaflet-based map with scene markers
|
|
2. **3D Panorama Viewer**: Pannellum for 360° image viewing
|
|
3. **User Authentication**: Registration, login with role-based access
|
|
4. **Privacy Controls**: Public, private, member-only, and shared scenes
|
|
5. **Image Processing**: Automatic resize to 8K (8192x4096) for consistency
|
|
6. **GPS Handling**: Extract original EXIF GPS, inject map coordinates
|
|
7. **Security**: Multi-layer protection against unauthorized access
|
|
8. **Share Links**: Token-based sharing for restricted content
|