Skip to content

AR Try-On — Internal Code Documentation

This document is intended for developers maintaining or extending the WEARFITS Node.js server. It covers system architecture, role-based access control, core processing flows, data and storage layers, ML models, environment configuration, deployment, and versioning.


1. System Architecture

WEARFITS uses a modular architecture where the core Express server handles routing and asset management, while specialized workers orchestrated via a custom queue system handle heavy computation (3D fitting, photogrammetry, baking).

graph TD
    subgraph Client
        SDK[JS SDK / Try-on Viewer]
        DASH[Dashboard UI]
    end

    subgraph Server ["Node.js / Express"]
        RT[Router / Controllers]
        MC[Modules Controller / Queue]
        SRV["src/ Service Layer"]
        PR[Prisma ORM]
    end

    subgraph Workers [Child Processes]
        WC[Converter Worker]
        WP[Photogrammetry Worker]
        WB[Bake / Blender Worker]
    end

    subgraph Data
        GCS[Google Cloud Storage]
        PG[(PostgreSQL)]
        JSON[Local JSON Database]
    end

    SDK <--> RT
    DASH <--> RT
    RT --> SRV
    SRV --> MC
    MC <--> WC & WP & WB
    SRV <--> PR <--> PG
    SRV <--> JSON
    SRV <--> GCS

A secondary view showing the full request path including external dependencies:

graph TD
    A[External Clients / Browser SDK] -->|HTTPS / WSS| B[Express Server]
    B --> C[Router / Controllers]
    C --> D["Service Layer / src"]
    D --> E[Prisma ORM]
    D --> F[Google Cloud Storage]
    D --> G[Local JSON DB / FS]
    E --> H[(PostgreSQL)]
    D --> I["External APIs: BoldMetrics, OpenAI"]
    B <--> J[Socket.io]

Key Components

Component File Responsibility
Entry point server.js Initializes Express, middleware (express-minify, compression), HTTP/HTTPS, Socket.io, and routes
Global config src/globals.js All directory paths, environment variables, bucket names, application constants, and proxy-based persistent config
Core utilities src/myUtils.js Bundle creation, script minification, thread execution, try-on version saving, addMesh() (triggers Slack notification on new model upload)
Threaded I/O src/myUtilsThreaded.js Promise-based file and cloud storage abstraction; switches between local FS and GCS via CLOUD_MODE
Worker control src/modules_controller.js Queue management and child-process lifecycle for converter, photogrammetry, and bake workers
WebSocket src/socketio.js Real-time progress events to clients
NextAuth bridge src/nextAuthSession.js Maps NextAuth session tokens to legacy user roles
Notifications src/notifications.js Non-blocking Slack webhook calls (new model uploads, etc.)

2. User Roles & Permissions

The application uses a numeric permission-level system combined with specific role flags stored on the user object.

Level Name Key Property Capabilities
1 User Authenticated Upload models; view personal objects
1.5 Low Admin lowAdmin: true Read-only access to global objects and status metrics
2 Garment Admin garmentAdmin: true Manage the photogrammetry queue (/queue_control)
3 Full Admin admin: true Complete access to /admin, /database-viewer, and global configurations

Authentication Providers

  1. Legacy — User data stored in var/database/users.json. Passwords hashed with bcrypt.
  2. NextAuth — Integrated with dash.wearfits.com. Users are resolved by email and mapped to legacy role flags via src/nextAuthSession.js.
  3. API Keys — Server-to-server authentication for integrators. Keys are validated against records in Prisma/PostgreSQL (ApiKey model).

Always verify permissions in route handlers before processing requests. Use the proxy pattern available in globals.persistent for all database interactions.


3. Core Logic Flows

3.1 Autofit & Upload Process

Triggered when a GLB file is uploaded via POST /tryon/api/upload_shoe:

Client uploads GLB
  └─► addModelFromGLBFile()       — saves file + textures to var/objects/
        └─► mc.queue.add('autofit') — pushes task to tryon queue
              └─► tryon worker       — Python/Blender scripts compute template foot alignment
                    └─► on_autofit_finished()
                          ├─► updates object properties in objects.json
                          └─► triggers 'bake' task if required
  1. addModelFromGLBFile persists the uploaded GLB and extracts textures.
  2. An autofit task is pushed to the tryon queue managed by modules_controller.
  3. The tryon worker (spawned child process running Python/Blender) computes foot alignment against the template.
  4. on_autofit_finished writes updated object properties back to objects.json and schedules a bake pass when necessary.
  5. src/notifications.js fires a non-blocking Slack webhook alert for new models (re-uploads are silently ignored).

3.2 Photogrammetry Task Flow

Triggered when a client uploads a ZIP archive of photos to POST /photogrammetry/upload:

Client uploads ZIP archive
  └─► Task record written to var/database/tasks.json
        └─► modules_controller picks up task
              └─► photogrammetry worker (child process)
                    ├─► emits Socket.io events: 'preprocessing' → 'building' → 'postprocessing'
                    └─► on success: 3D model moved to var/objects/
  1. The ZIP is validated and extracted by src/photogrammetry_utils.js (JPEG, PNG, and HEIC images only).
  2. A task record is persisted to var/database/tasks.json.
  3. modules_controller assigns the task to a photogrammetry worker.
  4. The worker emits granular progress events over Socket.io: preprocessing, building, postprocessing.
  5. On success the resulting 3D model is moved to var/objects/ and the task status is updated.

4. Database & Storage

4.1 Prisma (PostgreSQL)

Used primarily for modern authentication and API key management.

Model Purpose
User Authenticated dashboard user
Account OAuth provider account link
Session Active NextAuth session
ApiKey Server-to-server integration credentials
  • Schema: prisma/schema.prisma
  • Client generation: npx prisma generate (runs automatically on npm install)
  • Schema sync: npx prisma db push
  • GUI browser: npx prisma studio
  • Production secret: NEXTAUTH_DATABASE_URL stored in Google Cloud Secret Manager; the App Engine service account (wearfits-dev@appspot.gserviceaccount.com) requires the Secret Manager Secret Accessor role.

4.2 Legacy JSON Database

Core business data stored as JSON files in var/database/, loaded at startup and cached in globals.

File Global Cache Contents
objects.json globals.cachedObjectProperties All 3D model metadata
users.json Legacy user accounts and role flags
config.json globals.persistent App configuration, tryon version info
tokens.json Authentication tokens
tasks.json Photogrammetry task queue

4.3 Hybrid Storage via myUtilsThreaded.js

The storage abstraction layer provides a uniform API regardless of storage mode:

globals.CLOUD_MODE = true  →  operations target Google Cloud Storage
globals.CLOUD_MODE = false →  operations target local filesystem (var/)

init_storage() in myUtilsThreaded.js validates bucket existence at startup. If the main bucket is unreachable the system automatically falls back to local mode. Cloud operations are throttled to max_cloud_request_count = 200 to avoid rate limiting on batch operations.

router/assets.js issues res.redirect() to cloud URLs when CLOUD_MODE is enabled, meaning assets are served directly from GCS rather than proxied through the Node.js process.

4.4 GCS Bucket Structure

Global Variable Purpose
CLOUD_MAIN_BUCKET_NAME General asset storage (default)
CLOUD_SECURE_BUCKET_NAME Sensitive files
CLOUD_FR_BUCKET_NAME Fitting room assets
CLOUD_LABELER_BUCKET_NAME Image labeling data
CLOUD_PHOTOGRAMMETRY_BUCKET_NAME Photogrammetry processing files
CLOUD_MEASUREMENTS_BUCKET_NAME User measurement data

4.5 Local var/ Directory Layout

The var/ directory (root defined by globals.VAR_DIR, overridable via NODEJS_VAR) is the primary runtime storage location:

var/
├── objects/             # 3D model data
├── textures/            # Processed textures
├── usdz/                # USDZ exports
├── gltf/                # GLTF exports
├── tile_materials/      # Tiled material data
├── database/            # JSON database files (config.json, users.json, tokens.json)
├── ml_models/           # Cached ML model files
├── photogrammetry/      # Photogrammetry processing outputs
├── measurements/        # User measurement data
├── labeler/             # Labeling system data
├── fr/                  # Fitting room assets (cache, BVH, renderings, ZPAC)
├── tryon_versions/      # Versioned tryon app bundles (v1/, v2/, …, v{N}/)
├── tryon_bug_report/    # Try-on session bug reports
├── trash_bin/           # Soft-deleted items awaiting cleanup
├── tmp/                 # General temporary files (TMP_DIR)
└── tmp_fr/              # Fitting room temporary files (TMP_FR_DIR)

5. Project Structure

WEARFITS/
├── server.js                          # Main entry point: Express init, middleware, routes
├── src/                               # Core backend modules
│   ├── globals.js                     # Global config, paths, env vars, constants
│   ├── init_fs_and_logging.js         # Filesystem init and log stream setup
│   ├── myUtils.js                     # Core utilities: bundling, logging, addMesh()
│   ├── myUtilsThreaded.js             # Promise-based FS + GCS abstraction layer
│   ├── photogrammetry_utils.js        # Archive extraction and image preprocessing
│   ├── socketio.js                    # WebSocket connection management
│   ├── child.js                       # Child process management
│   ├── exporters.js                   # 3D model file export operations
│   ├── labeler_utils.js               # Labeling system utilities
│   ├── measurements_utils.js          # Measurement processing utilities
│   ├── modules_controller.js          # Worker module control and queue
│   ├── nextAuthSession.js             # NextAuth session integration
│   ├── notifications.js               # Non-blocking Slack webhook notifications
│   ├── tryon_utils.js                 # Try-on processing utilities
│   ├── wearfits_module_adapter.js     # Module adapter layer (Blob API compatibility)
│   └── workers.js                     # Worker thread management
├── router/                            # HTTP routes and controllers
│   ├── api.js                         # Main API endpoints
│   ├── assets.js                      # Static asset serving / cloud redirect
│   ├── fitting_room.js                # Fitting room functionality
│   ├── index.js                       # Main pages and access log
│   ├── account.js                     # Authentication and account management
│   ├── tryon.js                       # Try-on experience routes
│   ├── photogrammetry.js              # Photogrammetry upload and control routes
│   ├── labeler.js                     # Labeler routes
│   ├── measurements.js                # Measurements routes
│   ├── integrations.js                # Third-party integration routes
│   ├── server.js                      # Server management routes
│   └── tools.js                       # Utility tool routes
├── public/                            # Frontend assets (client-accessible)
│   ├── js/
│   │   ├── threejs/                   # Three.js libraries
│   │   ├── ml/                        # ML inference scripts
│   │   ├── onnx/                      # ONNX runtime files
│   │   ├── tf/                        # TensorFlow.js files
│   │   ├── wearfits-core.js           # Core frontend: 3D scene, camera, AR
│   │   ├── wearfits-editor.js         # Garment editor interface
│   │   └── tryon_static_files.js      # Static model ID → GCS URL mapping
│   ├── css/                           # Stylesheets
│   └── img/                           # Images and media
├── views/                             # EJS templates
│   ├── blocks/                        # Reusable template partials
│   ├── tryon.html                     # Try-on viewer entry point (GTM deferred load)
│   └── index.html                     # Main application entry point
├── scripts/                           # External processing tools (not in request cycle)
│   ├── digitise/
│   ├── measurement/
│   ├── photogrammetry/
│   ├── reality_capture/
│   ├── usdz_converter/
│   ├── ml_train/
│   └── …
├── prisma/
│   └── schema.prisma                  # Prisma database schema
├── tests/
│   ├── apiTests.js                    # API endpoint tests
│   └── README.md
├── .github/workflows/
│   ├── test.yml                       # Run tests on push to master
│   └── auto-version.yml               # Auto-increment build number on push
├── .githooks/
│   └── pre-push                       # Runs test suite before allowing push
├── app.yaml                           # GCP App Engine — production config
├── app_test.yaml                      # GCP App Engine — test environment config
└── package.json

Do not analyze files in scripts/, var/, or views/samples/ unless directly required. These are external tools or runtime artifacts.


6. ML Models

All inference runs client-side in the browser. Models are served from cloud storage and loaded by the SDK.

6.1 Supported Inference Formats

Format Browser Backends Notes
TensorFlow.js WebGL, CPU, WASM Default format; uses tf_backend option
ONNX WebGL, WebNN, CPU Enable with use_onnx=true; uses onnx_backend option
LiteRT (.tflite) WebGPU, WASM Via @litertjs/core; bundled as litert.bundle.js
Native Platform-specific High-performance path

6.2 Pose Detection Models

Model Path Suffix Size Input pose_quality Best For
Lite v2 pose_lite_v2/ ~5 MB 192×192 px 1 (default) Mobile, real-time
Full v2 pose_full_v2/ ~15 MB 256×256 px 2 Desktop, balanced
Heavy v2 pose_heavy_v2/ ~26 MB (7 shards) 256×256 px 3 Maximum accuracy

Outputs: 39 keypoints + segmentation mask + 3D coordinates (Heavy v2).

// Select via URL parameter
?pose_quality=3

// Or programmatically
tryon.options.pose_mode_model_type = "heavy"; // "lite" | "full" | "heavy"

Auto Target Pin Location (added Aug 2025): Set target_pin_location=auto (or ?target_pin_location=auto) to enable automatic switching between hand targets based on proximity.

6.3 Segmentation Models

Model Size Input Notes
seg_256_v1 ~8 MB (2 shards) 256×256 px Initial high-res segmentation
seg_256_v2 ~8 MB (2 shards) 256×256 px Improved accuracy
seg_256_v3 ~8 MB (2 shards) 256×256 px Latest optimized version

Models ≥256 px automatically enable full-crop mode (auto-cropping) for optimal input framing.

6.4 Footwear Detection Models

Medium series for footwear pose detection, available in multiple resolutions:

Resolution Versions ONNX Available
160×160 px v3, v4, v10 v4
192×192 px v4, v10 v4
256×256 px v3, v4, v10 v4, v10

ONNX filenames: medium_160_v4.onnx, medium_192_v4.onnx, medium_256_v4.onnx, medium_256_v10.onnx.

Configure resolution with:

tryon.options.native_ml_size = 256;      // 160 | 192 | 256
tryon.options.native_ml_point_set = 0;   // 0 | 1 | 2

6.5 Inference Performance

Model Desktop (ms) Mobile (ms) Memory (MB)
Lite Pose 15–25 40–80 50–100
Full Pose 25–40 80–150 100–200
Heavy Pose v2 40–70 150–300 200–400

6.6 Model Loading Times (Approximate)

Model Size WiFi 3G
Lite Pose 5 MB 2–3 s 8–12 s
Full Pose 15 MB 5–8 s 20–30 s
Heavy Pose v2 26 MB 8–12 s 35–50 s
Seg 256 v3 8 MB 3–5 s 12–18 s

6.7 Backend Configuration Reference

tryon.options = {
  // Model selection
  pose_mode_model_type: "full",          // "lite" | "full" | "heavy"
  native_ml_size: 192,                   // 160 | 192 | 256

  // Backend
  tf_backend: "webgl",                   // "webgl" | "cpu" | "wasm"
  onnx_backend: "webgl",                 // "webgl" | "cpu" | "webnn"
  use_onnx: false,
  webnn_enabled: false,                  // experimental

  // Quality & stability
  use_additional_masking_model: false,
  ignore_unstable_movements: true,
  oflow_error_threshold: 10.0,

  // Performance
  async_mode: false,
  target_pin_location: "auto",
};

7. Tech Stack

Component Technology
Runtime Node.js 24.x
Framework Express.js
Primary Database PostgreSQL via Prisma ORM
Secondary Database Local JSON files (var/database/)
Cloud Storage Google Cloud Storage
Real-time Socket.io v4
View Engine EJS
Image Processing Sharp v0.33
3D Rendering (client) Three.js
ML Inference (client) TensorFlow.js, ONNX Runtime, LiteRT
Notifications Slack Webhooks
External APIs OpenAI, BoldMetrics

8. Environment Variables

Variable Description Example / Default
PORT / NODEJS_HTTP_PORT Express HTTP port 8080
NODEJS_HTTPS_PORT Express HTTPS port 8443
NODEJS_VAR Override path for the var/ directory [project_root]/var
NEXTAUTH_DATABASE_URL Prisma connection string (PostgreSQL) prisma+postgres://…
GCP_SERVICE_ACCOUNT JSON credentials for GCP Service Account {…}
CLOUD_MAIN_BUCKET_NAME Main GCS bucket for assets wearfits-assets
CLOUD_SECURE_BUCKET_NAME GCS bucket for sensitive files
CLOUD_FR_BUCKET_NAME GCS bucket for fitting room assets
CLOUD_LABELER_BUCKET_NAME GCS bucket for labeling data
CLOUD_PHOTOGRAMMETRY_BUCKET_NAME GCS bucket for photogrammetry files
CLOUD_MEASUREMENTS_BUCKET_NAME GCS bucket for measurement data
WEARFITS_ORIGIN Base URL for the application https://app.wearfits.com
WEARFITS_CDN CDN URL for static assets https://cdn.wearfits.com
WEARFITS_PRODUCTION Production mode flag 1
OPENAI_API_KEY OpenAI API key sk-…
BOLDMETRICS_ID / BOLDMETRICS_KEY BoldMetrics API credentials
SLACK_WEBHOOK_URL Incoming webhook for Slack notifications https://hooks.slack.com/…

In production, NEXTAUTH_DATABASE_URL is stored in Google Cloud Secret Manager. The App Engine service account wearfits-dev@appspot.gserviceaccount.com must have the Secret Manager Secret Accessor role.


9. Deployment

9.1 Google Cloud Platform — App Engine (Flexible)

Config File Environment Notes
app.yaml Production (project: wearfits-dev) Use for all standard releases
app_test.yaml Test Staging/preview environment
app_prod.yaml Legacy Do not use for main production releases

9.2 CI/CD — GitHub Actions

Workflow Trigger Action
test.yml Push to master Runs full test suite
auto-version.yml Push to master Auto-increments build number

9.3 Git Hooks

A pre-push hook runs the test suite before any push is allowed. Enable it with:

git config core.hooksPath .githooks

9.4 CLI Reference

Command Description
npm start Start the application
npm run test Run all API tests
npm run test:api Run API-specific tests only
npm run test:db Verify JSON and Prisma DB connectivity
npm run test:all Run all available tests
npx prisma studio Launch the Prisma database GUI
npx prisma db push Sync Prisma schema with the database
npx prisma generate Regenerate Prisma client (after schema changes)
./build_docker.sh Build the Docker container
./run_docker.sh Run the Docker container

9.5 Development Guidelines

  • Variables: var for function scope, let for block scope, const for constants.
  • Modules: CommonJS (require / module.exports).
  • Naming: camelCase for variables and functions; PascalCase for classes.
  • Async: Prefer async/await over callbacks.
  • Error handling: try/catch blocks; log errors via myUtils.log(error, logname).
  • Logging: myUtils.log(data, globals.MODULE_LOG) for consistent module-level logging.
  • Database: Use the proxy pattern in globals.persistent for all database interactions.
  • Migrations: Always run npx prisma generate after changing prisma/schema.prisma.
  • Before pushing: Run npm run test:all.

10. Tryon Versioning

Tryon app assets are versioned automatically whenever any file in globals.tryon_files changes.

10.1 How It Works

  1. src/myUtils.js hashes all files listed in globals.tryon_files.
  2. The hash is compared against the stored tryon_version_hash in var/database/config.json.
  3. If the hash differs: the version counter is incremented, and all tryon files are copied to var/tryon_versions/v{N}/.

Each version directory contains: tryon.html, try-on.min.js, tryon_core.min.js, ML models, and all related static assets.

10.2 Version Configuration Keys (config.json)

Key Description
tryon_version Auto-incremented version counter
tryon_version_hash Hash of source files (change detection)
stable_tryon_version Default version served to end users
zara_tryon_version Version pinned for Zara
ccc_tryon_version Version pinned for CCC
inditex_mirror_tryon_version Version for Inditex mirror endpoints
inditex_mobile_tryon_version Version for Inditex mobile endpoints

10.3 Production Version History

Version Commit Date Notes
v477 98af1b6 2025-12-19 Current stable. Updated masking model. Deployed to all Inditex endpoints 2025-12-22.
v469 cdbf355 2025-12-03 Used for Inditex mobile endpoints before v477.
v434 8cd795d 2025-09-15 Hotfix 5456687 applied 2025-10-16 (mask fading fix). Used for Inditex mirror before v477.

10.4 Current Production Configuration (as of 2025-12-22)

Client Version
stable_tryon_version v477
inditex_mirror_tryon_version v477
inditex_mobile_tryon_version v477
inditex_mirror_accessory_tryon_version v477
inditex_mobile_accessory_tryon_version v477
zara_tryon_version v229
ccc_tryon_version v196

10.5 Git Tags

Major releases are tagged for easy checkout:

git checkout tryon-v477

11. Key Server-Side Libraries

Library Version License Purpose
@google-cloud/storage 7.0.1 Apache-2.0 Google Cloud Storage client
@prisma/client 5.22.0 Apache-2.0 Type-safe PostgreSQL database client
@prisma/extension-accelerate 3.0.1 Apache-2.0 Connection pooling and query caching
express 4.17.1 MIT Web application framework
socket.io 4.4.0 MIT Real-time bidirectional communication
sharp 0.33.4 Apache-2.0 High-performance server-side image processing
multer 1.4.5-lts.1 MIT Multipart/form-data file upload handling
bcrypt 5.0.0 MIT Password hashing
canvas 3.1.0 MIT Server-side canvas / image manipulation
ejs 3.1.6 Apache-2.0 Server-side HTML templating
draco3dgltf 1.5.5 Apache-2.0 3D mesh compression (Draco)
heic-convert 1.2.4 MIT HEIC → JPEG/PNG conversion
archiver 5.3.0 MIT ZIP/TAR archive creation
tar 6.2.0 ISC TAR archive handling
write-file-atomic 3.0.3 ISC Atomic file writes
node-cron 3.0.0 ISC Cron-based task scheduling
nodemailer 6.7.2 MIT Email sending
terser 5.36.0 BSD-2-Clause JavaScript minification
fs-extra 9.1.0 MIT Enhanced Node.js filesystem methods
compression 1.7.4 MIT Express response compression middleware

Client-Side Libraries (served from public/)

Library Purpose
three.js 3D scene rendering, OBJ/GLTF/USDZ loaders, shaders
tensorflow.js In-browser ML inference (WebGL / CPU / WASM backends)
onnx ONNX Runtime Web for cross-platform inference
@litertjs/core + @litertjs/tfjs-interop LiteRT.js for .tflite inference via WebGPU/WASM

12. Migration Roadmap (Express → Next.js)

The planned migration moves the web application and API from Express.js to a Next.js App Router architecture. External tools in scripts/ are out of scope.

Target Stack

Component Current Target
Framework Express.js Next.js with App Router
Frontend EJS templates + vanilla JS React components
Styling Custom CSS Tailwind CSS
API Express routes Next.js API routes
Real-time Socket.IO Socket.IO with Next.js adapter
3D (client) Three.js Three.js (retained)
Data Layer Direct file operations Abstracted data layer

Migration Phases

Phase 1 — Project Setup: New Next.js project, TypeScript, Tailwind, ESLint/Prettier, environment variable migration, Express-to-App-Router endpoint mapping.

Phase 2 — Data Layer Abstraction: Storage adapter interfaces for local FS and GCS; data models with Zod/Yup validation; JSON-to-structured-storage ETL.

Phase 3 — API Route Migration: Port all Express route handlers to Next.js API routes; maintain backward compatibility during transition.

Phase 4 — Frontend Migration: Convert EJS templates to React; migrate wearfits-core.js, wearfits-editor.js, and admin views.

Phase 5 — Real-time & Workers: Adapt Socket.IO for Next.js; evaluate serverless compatibility of child-process workers.

Key Migration Considerations for Filesystem Operations

Files performing filesystem I/O that require special attention in a serverless/edge context:

File Operations
src/init_fs_and_logging.js Directory creation, log stream setup
src/myUtils.js Log management, archive handling, temp file cleanup
src/myUtilsThreaded.js Full FS + GCS abstraction (primary I/O layer)
src/photogrammetry_utils.js Archive extraction, image preprocessing
router/assets.js Static file serving / cloud URL redirect
  • Move all server-only FS operations to API routes or server components.
  • Isolate GCS operations from Edge Runtime (not compatible with the GCP SDK).
  • The existing myUtilsThreaded.js abstraction layer should be preserved and adapted for Next.js constraints.
  • Audit public/js/tryon_static_files.js — it contains hard-coded GCS URLs that will need refactoring.