Files
3dtours/ARCHITECTURE.md
T

7.0 KiB

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

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

{
  username: String (unique, required),
  password: String (bcrypt hashed),
  role: Enum ['Chủ sở hữu', 'Thành viên'],
  timestamps: true
}

Scene Model

{
  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

{
  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