20260607 - login, add scene, add hotspot

This commit is contained in:
2026-06-07 21:31:31 +07:00
parent 10d2e07297
commit 5ba6e37039
29 changed files with 1064 additions and 73 deletions
+239
View File
@@ -0,0 +1,239 @@
# 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