← Back to s.plings.io Core Systems

Routing Logic

Created: Tue 29 Jul 2025 06:49:39 CEST
Document Version: 1.0 - Initial documentation
Security Classification: Public Technical Documentation
Target Audience: Frontend Developers, Product Managers
Author: Paul Wisén

Overview

The Director’s routing logic determines where to send users based on multiple factors including object status, user authentication, scan context, and business rules. This document details all routing scenarios and decision trees.

Routing Decision Flow

flowchart TD Start[Scan Received] --> Verify{Identifier Valid?} Verify -->|No| Error[Error Page] Verify -->|Yes| Lookup{Object Exists?} Lookup -->|No| Unknown{Generic or Manufacturer?} Unknown -->|Generic| Create[plings.io/create] Unknown -->|Manufacturer| Claim[plings.io/claim] Lookup -->|Yes| Status{Check Object Status} Status -->|FOR_SALE| Market[market.plings.io] Status -->|FOR_RENT| Rent[rent.plings.io] Status -->|LENDABLE| Lend[lend.plings.io] Status -->|LOST| Found[plings.io/found] Status -->|NORMAL| Auth{User Authenticated?} Auth -->|No & Public| View[plings.io/o/{id}] Auth -->|No & Private| Login[plings.io/login] Auth -->|Yes & Owner| Edit[plings.io/edit/{id}] Auth -->|Yes & Not Owner| View

Routing Rules by Object Status

FOR_SALE Objects

if (object.status === 'FOR_SALE') {
  return {
    service: 'market.plings.io',
    path: `/item`,
    params: {
      oid: object.id,
      price: object.salePrice,
      seller: object.owner.username
    }
  };
}

User Experience: Direct to marketplace listing with buy button

FOR_RENT Objects

if (object.status === 'FOR_RENT') {
  return {
    service: 'rent.plings.io',
    path: `/listing`,
    params: {
      oid: object.id,
      daily: object.rentPrice.daily,
      weekly: object.rentPrice.weekly
    }
  };
}

User Experience: Rental page with availability calendar

LENDABLE Objects

if (object.status === 'LENDABLE') {
  return {
    service: 'lend.plings.io',
    path: `/borrow`,
    params: {
      oid: object.id,
      terms: object.lendingTerms
    }
  };
}

User Experience: Peer-to-peer lending interface

LOST Objects

if (object.status === 'LOST') {
  return {
    service: 'plings.io',
    path: `/found`,
    params: {
      oid: object.id,
      location: scanLocation,
      timestamp: Date.now()
    }
  };
}

User Experience: “I found this item” flow with owner notification

Unknown Identifier Routing

Generic Plings Tags

Identification: Path starts with 1. (Plings manufacturer ID)

if (path.startsWith('1.') && !objectExists) {
  return {
    service: 'plings.io',
    path: '/create',
    params: {
      ikey: instanceKey,
      path: path,
      type: 'generic'
    }
  };
}

Manufacturer Pre-printed Tags

Identification: Non-Plings manufacturer ID with class pointer

if (!path.startsWith('1.') && classPointer && !objectExists) {
  return {
    service: 'plings.io',
    path: '/claim',
    params: {
      ikey: instanceKey,
      path: path,
      class: resolvedClassId,
      cptr: classPointer,
      manufacturer: manufacturerName
    }
  };
}

Authentication-Based Routing

Owner Scanning Own Object

if (isAuthenticated && object.owner === user.id) {
  return {
    service: 'plings.io',
    path: `/edit/${object.id}`,
    params: {
      context: 'owner_scan',
      quickActions: true
    }
  };
}

Public Scanning Private Object

if (!isAuthenticated && object.visibility === 'private') {
  return {
    service: 'plings.io',
    path: '/login',
    params: {
      return: `/o/${object.id}`,
      reason: 'private_object'
    }
  };
}

Context-Aware Routing

A/B Testing

const testGroup = hashUserId(userId) % 100;

if (testGroup < 10) { // 10% of users
  return experimentalRoute;
} else {
  return standardRoute;
}

Geographic Routing

const userRegion = geoIP.getRegion(request.ip);

const regionalServices = {
  'EU': 'eu.plings.io',
  'US': 'us.plings.io',
  'ASIA': 'asia.plings.io'
};

return {
  service: regionalServices[userRegion] || 'plings.io',
  // ... rest of routing
};

Time-Based Routing

if (isMaintenanceWindow()) {
  return {
    service: 'status.plings.io',
    path: '/maintenance',
    params: {
      estimatedTime: getMaintenanceEnd()
    }
  };
}

Special Routing Scenarios

Business Hours Routing

if (object.type === 'BUSINESS_ASSET' && !isBusinessHours()) {
  return {
    service: 'plings.io',
    path: '/business-hours',
    params: {
      openTime: getNextOpenTime(),
      contact: object.businessContact
    }
  };
}

Emergency Services

if (object.tags.includes('MEDICAL') || object.tags.includes('EMERGENCY')) {
  return {
    service: 'plings.io',
    path: '/emergency',
    params: {
      type: object.emergencyType,
      contact: object.emergencyContact,
      priority: 'HIGH'
    }
  };
}

Compliance Routing

if (userRegion === 'EU' && !hasGDPRConsent(user)) {
  return {
    service: 'plings.io',
    path: '/privacy-consent',
    params: {
      return: originalRoute,
      region: 'EU'
    }
  };
}

Parameter Enrichment

All routes include enriched parameters:

function enrichParameters(baseParams: Params, context: Context): EnrichedParams {
  return {
    ...baseParams,
    // Always included
    src: 'scan',
    ikey: context.instanceKey,
    path: context.path,
    
    // Conditional
    ...(context.objectId && { oid: context.objectId }),
    ...(context.classPointer && { cptr: context.classPointer }),
    ...(context.hasLocation && { loc: context.location }),
    ...(context.isAuthenticated && { session: context.sessionId }),
    
    // Analytics
    ts: Date.now(),
    v: '1.0' // API version
  };
}

Error Routing

Invalid Identifier

if (!isValidIdentifier(instanceKey)) {
  return {
    service: 'plings.io',
    path: '/scan-error',
    params: {
      reason: 'invalid_identifier',
      help: 'Check if this is a valid Plings QR code'
    }
  };
}

Rate Limited

if (isRateLimited(request.ip)) {
  return {
    service: 'plings.io',
    path: '/scan-error',
    params: {
      reason: 'rate_limit',
      retryAfter: getRateLimitExpiry(request.ip)
    }
  };
}

System Error

catch (error) {
  logError(error);
  return {
    service: 'plings.io',
    path: '/scan-error',
    params: {
      reason: 'system_error',
      code: error.code || 500,
      support: 'support@plings.io'
    }
  };
}

Routing Priority

When multiple routing rules apply, this priority order is followed:

  1. Security & Compliance (GDPR, rate limits)
  2. System Status (maintenance, outages)
  3. Object Status (FOR_SALE, LOST, etc.)
  4. User Context (authenticated, owner)
  5. Business Rules (hours, geography)
  6. Default Routes

Configuration

Routing rules can be configured via environment variables:

# Service URLs
MAIN_SERVICE_URL=https://plings.io
MARKET_SERVICE_URL=https://market.plings.io
RENT_SERVICE_URL=https://rent.plings.io

# Feature Flags
ENABLE_AB_TESTING=true
ENABLE_GEO_ROUTING=true
ENABLE_BUSINESS_HOURS=false

# Routing Rules
DEFAULT_UNKNOWN_ROUTE=/create
MAINTENANCE_ROUTE=/status

Monitoring

Key metrics tracked for routing decisions: