Architecture Deep Dive

This section provides an in-depth exploration of WTicket’s system architecture, design decisions, and technical implementation details.

System Architecture Overview

WTicket employs a modern three-tier architecture optimized for serverless deployment and scalability. The architecture prioritizes simplicity, maintainability, and cost efficiency while delivering enterprise-grade functionality.

Architecture Principles:

  1. Separation of Concerns: Clear boundaries between presentation, logic, and data layers

  2. Stateless Design: Each request contains all information needed for processing

  3. Cache-First Strategy: Local caching reduces network requests and improves responsiveness

  4. Graceful Degradation: Application continues functioning during network interruptions

Technology Layer Mapping:

Client-Side Architecture

### Module Structure

The application consists of seven core modules, each responsible for specific functionality:

Core Modules:

js/
├── app.js           # Central API and business logic
├── toast.js         # User notification system
├── shortcuts.js     # Keyboard shortcut handling
├── utils.js         # Shared utility functions
├── db.js            # IndexedDB cache management
├── i18n.js          # Internationalization
└── achievements.js   # Gamification system

Module Dependencies:

app.js (Core)
   ├── toast.js
   ├── shortcuts.js
   ├── utils.js
   ├── db.js
   ├── i18n.js
   └── achievements.js

### Page Architecture

Six HTML pages serve distinct user journeys:

Public Pages:

  • index.html: Landing page with public statistics

  • contact.html: Developer contact information

Authenticated Pages:

  • login.html: Authentication gateway

  • dashboard.html: User ticket management

  • admin.html: Administrator control panel

  • profile.html: Account settings and achievements

### Data Flow Architecture

User Action
     │
     ▼
HTML Event Handler
     │
     ▼
JavaScript Module
     │
     ├──► IndexedDB Cache (immediate read)
     │
     ▼
JSONBin.io API (async)
     │
     ▼
Server Response
     │
     ▼
Update Cache ──► Update UI
     │
     ▼
Display Result

Data Layer Design

### JSONBin.io Integration

JSONBin.io serves as the primary persistent data store, providing RESTful access to JSON documents.

Bin Structure:

API Operations:

// Read operation
GET /b/{bin_id}/latest
Headers: X-Master-Key: {api_key}

// Write operation
PUT /b/{bin_id}
Headers:
    X-Master-Key: {api_key}
    Content-Type: application/json
Body: { json_data }

### Synchronization Strategy

The sync-before-write pattern prevents data loss from concurrent operations.

The Problem:

When multiple users operate simultaneously, naive write operations can overwrite concurrent changes.

The Solution:

async function safeWrite(binId, localData) {
    // 1. Fetch latest server state
    const serverData = await fetchLatest(binId);

    // 2. Merge changes (local takes precedence)
    const mergedData = merge(serverData, localData);

    // 3. Write merged data
    await writeToServer(binId, mergedData);

    // 4. Update local cache
    localCache = mergedData;
}

### IndexedDB Caching

IndexedDB provides client-side persistence for offline access and performance optimization.

Database Schema:

Database: wticket_db (version 1)

Object Stores:
├── users
   └── keyPath: email
├── tickets
   └── keyPath: id
├── counter
   └── keyPath: id
└── sync
    └── keyPath: type

Cache Operations:

  • cacheUsers(): Persist user data locally

  • getCachedUsers(): Retrieve cached user data

  • cacheTickets(): Store tickets for offline access

  • getCachedTickets(): Access cached ticket data

  • cacheCounter(): Preserve ID sequence

  • getCachedCounter(): Retrieve cached counter value

### localStorage Usage

Session and preference data use localStorage for immediate access.

Stored Items:

  • Session token and user information

  • Theme preference (light/dark)

  • Language preference (es/en)

  • Last sync timestamps

Authentication Architecture

### Session Management

Sessions provide authenticated state across page navigations.

Session Lifecycle:

  1. Creation: User submits credentials

  2. Validation: Server (JSONBin) validates against stored hash

  3. Token Generation: 256-bit cryptographically random token created

  4. Storage: Token stored in localStorage

  5. Validation: Token checked on each authenticated action

  6. Expiration: Token expires after 24 hours

  7. Cleanup: Expired tokens trigger re-authentication

Session Object Structure:

{
    token: "a1b2c3d4e5f6...",  // 256-bit secure token
    email: "user@example.com",
    name: "John Doe",
    role: "user",               // or "admin"
    createdAt: 1711459200000,   // Unix timestamp
    expiresAt: 1711545600000    // 24 hours later
}

### Password Security

Passwords undergo client-side hashing before transmission and storage.

Hashing Process:

async function hashPassword(password) {
    const salt = 'wticket_salt';
    const data = new TextEncoder().encode(password + salt);
    const hashBuffer = await crypto.subtle.digest('SHA-256', data);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

Security Considerations:

  • Salt prevents rainbow table attacks

  • SHA-256 is computationally intensive

  • Client-side hashing does not replace server-side bcrypt

  • Transport over HTTPS is mandatory

Role-Based Access Control

### User Roles

Two roles provide appropriate access levels:

User Role:

  • Create tickets

  • View own tickets

  • Add comments to own tickets

  • Update own profile

  • View own achievements

Admin Role:

  • All user permissions plus:

  • View all tickets

  • Close any ticket

  • Assign tickets to admins

  • Export ticket data

  • View system statistics

### Authorization Decorator

The requireAuth() decorator enforces access control:

async function requireAuth(allowedRoles) {
    return async function() {
        const session = await validateSession();

        if (!session) {
            redirectToLogin();
            return null;
        }

        if (!allowedRoles.includes(session.role)) {
            showUnauthorizedError();
            return null;
        }

        return session;
    };
}

Presentation Layer Architecture

### CSS Design System

A comprehensive design system ensures visual consistency.

Design Tokens:

:root {
    /* Colors */
    --primary: #6366f1;
    --primary-hover: #4f46e5;
    --success: #10b981;
    --warning: #f59e0b;
    --danger: #ef4444;

    /* Typography */
    --font-family: 'Inter', system-ui, sans-serif;
    --font-size-base: 16px;

    /* Spacing */
    --spacing-unit: 4px;
    --spacing-sm: 8px;
    --spacing-md: 16px;
    --spacing-lg: 24px;

    /* Borders */
    --border-radius: 8px;
    --border-color: #e5e7eb;

    /* Shadows */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
}

### Dark Mode Implementation

Theme switching uses CSS custom properties and data attributes.

Implementation:

function toggleTheme() {
    const current = document.documentElement.getAttribute('data-theme');
    const newTheme = current === 'dark' ? 'light' : 'dark';
    document.documentElement.setAttribute('data-theme', newTheme);
    localStorage.setItem('theme', newTheme);
}

CSS Variables for Dark Mode:

[data-theme="dark"] {
    --bg-primary: #111827;
    --bg-secondary: #1f2937;
    --text-primary: #f9fafb;
    --text-secondary: #d1d5db;
    --border-color: #374151;
}

### Responsive Breakpoints

Mobile-first design with progressive enhancement.

Breakpoints:

  • < 640px: Mobile devices

  • 640px - 768px: Small tablets

  • 768px - 1024px: Tablets

  • > 1024px: Desktops

### Navigation Architecture

Segmented navigation improves usability on all devices.

Desktop Layout:

[Hamburger] [Logo] | [Nav Links] ..................... [User] [Theme] [Actions]

Mobile Layout:

[Hamburger] [Logo]

Slide-out drawer on hamburger click:
┌─────────────────────────┐
│ [User Info]             │
│─────────────────────────│
│ Inicio                  │
│ Contacto                │
│ Mi Perfil               │
│─────────────────────────│
│ 🌙 Theme    🔄 Refresh │
│ 🚪 Logout              │
└─────────────────────────┘

Progressive Web App Architecture

### Service Worker Strategy

Service workers enable offline functionality and performance optimization.

Caching Strategy:

  • Cache-First: Static assets (HTML, CSS, JS, images)

  • Network-First: Dynamic data (JSONBin requests bypassed)

  • Stale-While-Revalidate: Best effort with cache fallback

Cached Assets:

const CACHE_NAME = 'wticket-v3';
const STATIC_ASSETS = [
    'index.html',
    'login.html',
    'dashboard.html',
    'admin.html',
    'profile.html',
    'contact.html',
    'css/styles.css',
    'js/app.js',
    'js/toast.js',
    'js/shortcuts.js',
    'js/utils.js',
    'js/db.js',
    'js/i18n.js',
    'js/achievements.js',
    'manifest.json'
];

### Web App Manifest

The manifest enables installation on home screens.

Manifest Properties:

{
    "name": "WTicket - Sistema de Tickets",
    "short_name": "WTicket",
    "start_url": "/",
    "display": "standalone",
    "background_color": "#f3f4f6",
    "theme_color": "#6366f1",
    "icons": [
        {
            "src": "/icon-192.png",
            "sizes": "192x192",
            "type": "image/png"
        }
    ],
    "shortcuts": [
        {
            "name": "Crear Ticket",
            "url": "/login.html?tab=register"
        }
    ]
}

Error Handling Architecture

### API Error Handling

Consistent error handling provides clear feedback.

Error Categories:

  • Network Errors: Connection failures, timeouts

  • Authentication Errors: Invalid credentials, expired sessions

  • Validation Errors: Invalid input data

  • Server Errors: JSONBin service issues

Error Handler Implementation:

async function safeApiCall(apiFunction) {
    try {
        return await apiFunction();
    } catch (error) {
        if (error.name === 'NetworkError') {
            Toast.error('Network connection failed. Please check your internet.');
        } else if (error.message.includes('Session')) {
            redirectToLogin();
        } else {
            Toast.error(`Error: ${error.message}`);
        }
        throw error;
    }
}

### UI Error States

Graceful degradation maintains user experience during errors.

Error States:

  • Empty States: No data to display

  • Loading States: Data being fetched

  • Error States: Operation failed

  • Offline States: No network connectivity

Performance Optimization

### Code Splitting

Modules load on demand, reducing initial bundle size.

Deferred Modules:

  • achievements.js: Loaded only on profile page

  • i18n.js: Loaded only when language switching needed

### Debouncing and Throttling

Input handling optimizes performance.

Search Input:

const debouncedSearch = debounce((query) => {
    filterTickets(query);
}, 300);

Refresh Button:

const throttledRefresh = throttle(() => {
    loadTickets();
}, 1000);

### Lazy Loading Images

Images below viewport load on scroll.

Implementation:

<img data-src="image.jpg" class="lazy" alt="Description">
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            entry.target.src = entry.target.dataset.src;
            observer.unobserve(entry.target);
        }
    });
});

Extensibility Points

### Adding New Modules

Extend functionality by creating new modules.

Module Template:

// js/newModule.js
export function newFeature() {
    // Implementation
}

// Import in app.js
import { newFeature } from './newModule.js';

### Custom Themes

Create custom themes by extending CSS variables.

Theme File Template:

[data-theme="custom"] {
    --primary: #custom-color;
    --primary-hover: #custom-hover;
    /* Override other variables */
}

### API Extensions

Extend the API with custom functions.

Extension Pattern:

// In app.js
export const extendedAPI = {
    ...API,
    customFunction: async (param) => {
        // Custom implementation
    }
};