hm_ems_report/CLAUDE.md
Vadym Samoilenko 75d5519215 Update paths for production domain and HTTPS
Changed application path from /hm-ems/ to /hm-ems-report/ to match production URL structure. Updated all references to use HTTPS and correct domain.

Changes:
- Path prefix: /hm-ems/ → /hm-ems-report/
- Production URL: https://ai-sandbox.oliver.solutions/hm-ems-report/
- Created apache/hm-ems-report.conf with full Apache configuration
- Updated all API and image paths in frontend and backend
- Updated documentation with correct URLs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 21:33:46 +00:00

6.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

H&M EMS Product Review Tool - A web-based application for reviewing and editing H&M product data across multiple languages. The tool allows clients to review product names and prices, make inline edits, approve changes, and save them back to master JSON files with full change logging.

Architecture

Two Operation Modes

  1. Server Mode (server.py): Live Flask web app with API endpoints for real-time editing, approval, and saving back to master JSON
  2. Static Generator Mode (html_generator.py): Generates self-contained HTML files with embedded data (can be run standalone)

Core Components

  • server.py: Flask backend serving API endpoints and static files

    • Thread-safe JSON read/write operations using file_lock
    • Change logging to *_changelog.json files alongside master JSON
    • Image serving with path traversal protection
  • html_generator.py: Shared utilities and standalone HTML generator

    • LANGUAGE_DISPLAY_NAMES: 60+ language/locale display mappings
    • Helper functions for campaign prefix extraction and image filename processing
    • When run standalone, generates fully self-contained HTML with embedded JS/CSS
  • static/index.html: Client-side review UI

    • Dynamic column management (up to 4 target languages side-by-side)
    • Inline editing with real-time change tracking
    • Approve/unapprove workflow with field locking
    • Multi-image support with click-to-enlarge

Data Flow

Master_Json/{campaign}.json
    ↓ (loaded by server or generator)
Campaign data grouped by Article ID
    ↓ (processed with image mapping)
Frontend table with editable fields
    ↓ (on approve)
POST /api/approve → updates master JSON + appends changelog

Image Handling

  • Source: .tif files listed in JSON Filename field (comma-separated for multi-image articles)
  • Conversion: .tif.jpg (handled by image path helpers)
  • Location: campaign_images/{year}/{campaign}/Automation_LR/
  • Year derivation: First 4 digits of Season field (e.g., "202502" → "2025")
  • Campaign prefix: Text before first underscore in JSON filename (e.g., "1022A.json" → "1022A")

Approval & Changelog System

  • Approval state: Tracked per Article ID + Language combination
  • Changelog format: {campaign}_changelog.json stores timestamped entries with:
    • Article ID, Language, Country, Product ID
    • Action: "approve" or "unapprove"
    • Edits array: field name, old value, new value
  • Approval persistence: On load, changelog is replayed to rebuild approval state
  • Thread safety: All JSON writes use file_lock to prevent concurrent modification

Development Commands

Local Development Setup

# Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate

# Install dependencies
pip install -r requirements.txt

# Run locally
python3 server.py
# Opens on http://localhost:5000

Production Deployment

Application runs on Ubuntu with Apache reverse proxy. See DEPLOY.md for full instructions.

Quick deploy:

cd /opt/hm_ems_report
sudo ./deploy.sh

Architecture:

  • Flask/Gunicorn runs as systemd service on port 5000 (localhost only)
  • Apache serves static files from /var/www/html/hm-ems-report/
  • Apache proxies /hm-ems-report/api/* to Flask backend
  • Apache serves images directly from /opt/hm-ems-data/campaign_images/
  • Data persisted in /opt/hm-ems-data/ (JSON files + images)

Production URL:

  • Web UI: https://ai-sandbox.oliver.solutions/hm-ems-report/
  • API: https://ai-sandbox.oliver.solutions/hm-ems-report/api/*
  • Images: https://ai-sandbox.oliver.solutions/hm-ems-report/images/*

Run with Gunicorn (production)

gunicorn server:app --bind 0.0.0.0:5000 --workers 4

Generate standalone HTML site

python html_generator.py <json_file> [output_dir] [image_base_path]
# Example:
python html_generator.py Master_Json/1022A.json ./html_output/1022A ./campaign_images

Configuration

All paths configurable via environment variables:

  • MASTER_JSON_DIR: Campaign JSON files location (default: ./Master_Json)
  • IMAGE_BASE_PATH: Root folder for {year}/{campaign}/Automation_LR/ images (default: ./campaign_images)
  • PORT: Server port (default: 5000)

Example:

IMAGE_BASE_PATH=/custom/images MASTER_JSON_DIR=/custom/json PORT=8080 python3 server.py

API Endpoints

Method Endpoint Purpose
GET / Serve review UI
GET /api/files List available campaign JSON files (excludes *_changelog.json)
GET /api/load/<filename> Load campaign data with image map, languages, approvals
POST /api/approve Approve/unapprove record, apply edits to master JSON, log changes
GET /images/<year>/<campaign>/<file> Serve campaign images (with path traversal protection)

Adding New Campaigns

  1. Place JSON file in Master_Json/ (e.g., 3045A.json)
  2. Place images in campaign_images/{year}/{campaign}/Automation_LR/
    • Year: First 4 digits of Season field in JSON
    • Campaign: Text before first underscore in filename
  3. Refresh browser - new campaign appears in dropdown

Key Implementation Details

Security

  • Path traversal protection: All file/image paths use os.path.basename() before joining
  • Changelog files excluded from campaign list (filter _changelog.json)

Frontend State Management

  • langColumns array: Dynamic language column configuration (up to 4)
  • changes object: Keyed by {articleId}::{lang}::{field} for tracking edits
  • approvals object: Keyed by {articleId}::{lang} for approval state
  • Trailing empty dropdown: Automatically added when columns < 4 and last is filled

Data Grouping

  • Records grouped by Article ID (each article has multiple language variants)
  • English (GB) always shown as reference column (non-editable)
  • Product name field highlights when differs from English (case-insensitive comparison)

Concurrency

  • threading.Lock() ensures safe concurrent JSON read/write operations
  • Changelog append is atomic within the lock scope