CLAUDE.md

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

Project Overview

This is a multilingual Jekyll website for Mirigi, a digital concierge service for condominiums. The site showcases features and customer testimonials in English, Spanish, and French. It’s built using Jekyll with a Bootstrap-based theme and Docker deployment.

Sibling reference repositories (read-only, for grounding marketing claims)

When fact-checking or extending any feature/FAQ/copy, ground claims against the actual implementation. The three sibling repos cover the three product surfaces:

Repo Path (local sibling) Tech Use it to verify…
Backend /home/fede/repos/mirigi/mirigi/mirigi-backend/ Python (app/) Source of truth. Endpoints, business logic, state machines, AI tools (mirigi_* in app/resident/ws/v2/ai_chat.py), event constants, schema, all real capabilities. Search app/staff/, app/resident/, app/model/ for grounding.
Resident frontend /home/fede/repos/mirigi/mirigi-frontend/ React What residents see/do. Use to verify the resident-side UI for any feature claim.
Staff portal /home/fede/repos/mirigi/mirigi-staff/ React 19 + Vite + TypeScript + Tailwind v4, runs on :3001, see src/pages/ and src/api/ What staff and management see/do. Use to verify staff-console claims (operations dashboards, reports, valet queue, package log, role-based access).

Grounding rule: if a claim names a specific capability — “residents can ask Miri to book the amenity”, “the staff console flags packages for pickup”, “boards run custom reports on demand” — open the matching repo and verify the endpoint/page/tool exists before publishing. If it doesn’t, soften the claim or remove it. The fact-check agents dispatched from this repo have explicit access to all three paths above.

Marketing Copy Rules

Never mention technical internals on feature pages, customer pages, brochures, or proposals. The audience is luxury condominium boards, property managers and residents — not developers. Describe the experience (what the user sees and gets), not the mechanism (how the code does it).

When summarizing or fact-checking content, replace technical names with the user-visible behavior they enable:

Internal / technical term User-facing replacement
MQTT, WebSocket, long-polling “real-time updates” / “live notifications”
Twilio, SMS provider names “SMS”
Cordova, Capacitor, React Native (framework) “companion app” / “branded mobile app”
MJPEG, RTSP, ONVIF, HLS, HTTP video endpoint “video streams”
OAuth, OAuth 2.0, OAuth pairing, SSO protocol names “pairs securely” / “secure API”
RSA, PKCS, JWT, signed JWT “cryptographically signed” / “secure”
S3, blob storage, CDN “secure storage”
MIME, multipart, base64 omit, or “file upload”
HTTP, REST, JSON, GraphQL “secure API” / “integration”
SQL query, database query, raw query “fully customizable” / “tailored to the property” / “defined per building” — do not name the authoring mechanism
Prosis, administracion.com.uy (vendor) “the administrator’s accounting platform”
BLI, BeoLiving Intelligence (technical name) “smart-home controller” (when audience won’t recognize BLI). BLI/Khimo OK on the home automation page itself — they are brand-marketed by Bang & Olufsen and recognized by integrators.
Axis (camera brand), specific camera models “IP cameras”

Always-forbidden (regardless of context — off-brand or false):

Always-OK technical terms (widely understood, marketing-friendly):

When in doubt: “Residents are notified the moment their car is ready” beats “the system pushes an MQTT event on state change”.

Development Commands

Primary Development Workflow

# Build and serve using Docker (recommended)
docker build -t mirigi-jekyll-site .
docker run -v $(pwd):/usr/src/app -p 4000:4000 mirigi-jekyll-site

# Or use the Makefile (requires docker image to be built first)
make serve

# For frontend asset development (SCSS/JS changes)
npm install
npm run start        # Runs gulp watch with BrowserSync on port 3000

Build Commands

make all            # Build frontend assets using gulp (runs npm install if needed)
gulp build          # Build CSS/JS assets and copy vendor dependencies
gulp css            # Compile SCSS only
gulp vendor         # Copy node_modules dependencies to /vendor/

Architecture & Structure

Multilingual Setup

Key Directories

Layout Hierarchy

Content Management

Features and customers are Jekyll collections. Each content piece requires this frontmatter:

---
title: "Feature Name"
image: "/img_mirigi/feature-image.jpg"
layout: feature  # or "customer"
description: "Short description for SEO"
keywords: keyword1, keyword2, keyword3
image_credits: '@<a href="url">author</a>'  # optional
---

The lang and permalink are auto-set by _config.yml defaults based on file path.

Frontend Build Process

Multilingual Content Pattern

When adding content, create the same file (same filename) in all three language directories:

Brochure System

brochure.html is a static, print-optimized marketing brochure (US Letter, 8.5”×11”). Styled by scss/_brochure.scss with luxury typography (Playfair Display, Montserrat) and a dark charcoal/pearl/gold palette.

Key SCSS variables:

$print-page-height: 11in
$print-page-width: 8.5in
$print-margin: 0.5in
$brochure-dark-bg: #58595b
$brochure-light-bg: #f5f5f5

Key CSS classes:

The same CSS framework and components (_includes/brochure_feature.html, _includes/brochure_customer.html) are reused in proposal.html for dynamic proposals.

Proposal System

The site includes a sales proposal generator system that allows salespeople to create customized PDF proposals for buildings.

JS Module Roles

Proposal Output Sections (proposal.html)

Decrypts ?d= URL parameter and dynamically renders:

  1. Cover (building name, tagline, salesperson, date)
  2. About Mirigi
  3. Highlighted features (2/page, alternating left-right layout)
  4. Compact features grid (non-highlighted features)
  5. Pricing (platform + one-time services)
  6. Terms (timeline, notes, valid-until)
  7. Customers grid
  8. Next Steps / Contact

Authentication & Encryption Method

The proposal system uses a key-based authentication with encrypted URL parameters:

Authentication Flow:
1. User enters symmetric key (only the user knows it - NOT stored in code)
2. localStoredKey = HMAC-SHA256(symmetricKey, SALT)
3. accessHash = HMAC-SHA256(localStoredKey, SALT)
4. Verify: accessHash === ACCESS_HMAC (pre-calculated constant in code)
5. encryptionKey = HMAC-SHA256(localStoredKey, "encrypt") - for AES encryption

SALT = "mirigi is the best smartbuilding solution"
ACCESS_HMAC = "c5a1de2293c3aed54d86479d5e8df92a685a97aadcde11563491a7fc8d17af5c"

Security properties:

Key derivation:

// Login verification (symmetric key only exists in user's memory)
localStoredKey = HMAC(userEnteredKey, SALT)
accessHash = HMAC(localStoredKey, SALT)
isValid = (accessHash === ACCESS_HMAC)  // ACCESS_HMAC is pre-calculated constant

// Encryption key derivation
encryptionKey = HMAC(localStoredKey, "encrypt")  // Used for AES-GCM

To change the access key: Calculate new ACCESS_HMAC offline:

node -e "
const crypto = require('crypto');
const SALT = 'mirigi is the best smartbuilding solution';
const newKey = 'YOUR_NEW_KEY';
const localKey = crypto.createHmac('sha256', SALT).update(newKey).digest('hex');
const ACCESS_HMAC = crypto.createHmac('sha256', SALT).update(localKey).digest('hex');
console.log('ACCESS_HMAC:', ACCESS_HMAC);
"

Proposal Builder Pages

All three language versions use the shared layout with just frontmatter:

Login Translations

Login UI strings are in _data/[lang].yml: