# Kaissa Kstych - Technical Specifications

**Version**: 1.10.0
**Last Updated**: April 15, 2026
**Status**: ONLINE (Dev) — PM2 on port 3011; nginx/DNS can be re-enabled

---

## Admin User

- Admin user email: `admin@fourayam.com`


## Overview

Kaissa Kstych is an Express.js web service deployed at https://kaissa.ksty.ch. It serves as a platform service under the Kaissa Global ecosystem.

- **Kaissa**: AI Agent Platform for intelligent automation
- **Kstych**: Kubernetes CLI tool for K8S management

**Base URL**: `https://kaissa.ksty.ch`
**Protocol**: HTTPS
**Port**: 3011 (internal)

## Architecture

### Technology Stack
- **Runtime**: Node.js v22
- **Framework**: Express.js
- **Process Manager**: PM2
- **Reverse Proxy**: Nginx with SSL/TLS

### Security Features
- Helmet security headers
- CORS protection
- Response compression
- Morgan HTTP logging
- **Cloudflare Turnstile** human verification
- **Cloudflare Country Detection** via CF-IPCountry header

### Frontend Features
- **Video Gallery**: 25 videos in responsive grid
- **Desktop**: 3-column layout, hover to play (muted)
- **Tablet**: 2-column layout
- **Mobile**: 1-column layout, auto-play on scroll (muted)
- **Click**: Redirects to WhatsApp chat with Nova (+12086460727)
- Scroll-synced video background
- PWA-ready icons

## Security

### Cloudflare Turnstile Integration

**Site Key**: `0x4AAAAAACd5D5X4B7_u7IDS`
**Mode**: Managed
**Domain**: kaissa.ksty.ch

### Cloudflare Headers Used
- `CF-IPCountry`: Visitor country code (ISO 3166-1 alpha-2)
- `CF-IPCity`: Visitor city (when available)
- `CF-Region`: Visitor region (when available)
- `CF-Connecting-IP`: Visitor IP address

## API Endpoints

### Authentication (Google OAuth)

- GET /auth/google — starts OAuth flow (requires GOOGLE_CLIENT_ID/SECRET)
- GET /auth/google/callback — OAuth callback
- GET /api/me — returns `{ user }` when authenticated; 401 when not logged in
- POST /logout — clears session

Env:
- SESSION_SECRET
- GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_CALLBACK_URL (default http://localhost:3011/auth/google/callback)

---

### Billing (Stripe Checkout)

- POST /api/billing/checkout
  - Body: `{ type: "phone"|"recharge" }`
  - Returns: `{ url }` (Stripe Checkout Session URL)
  - 503 when STRIPE_SECRET_KEY missing; 400 for invalid input/config

- POST /webhooks/stripe
  - Expects: `Stripe-Signature` header (with STRIPE_WEBHOOK_SECRET configured)
  - Purpose: handle `checkout.session.completed` / `payment_intent.succeeded` (idempotent credit updates)

Env:
- STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET
- STRIPE_PRICE_PHONE, STRIPE_PRICE_RECHARGE
- CHECKOUT_SUCCESS_URL, CHECKOUT_CANCEL_URL

---

### TextVerified Wrapper (API v2)

- GET /api/tv/balance — returns account balance (503 if TEXTVERIFIED_API_KEY missing)
- POST /api/tv/purchase — purchases a US number/rental
  - Body: `{ service: string, region?: "US" }`
  - 400 when missing service; 503 when not configured

Env:
- TEXTVERIFIED_API_KEY
- TEXTVERIFIED_BASE (default https://www.textverified.com/api/v2)

---

### GET /health
System health check.

**Response:**
```json
{
  "status": "ok",
  "service": "kstych",
  "timestamp": "2026-02-16T12:00:00.000Z",
  "uptime": 12345.678
}
```

---

### GET /api/status
Service status and version.

**Response:**
```json
{
  "service": "Kaissa Kstych",
  "version": "1.1.0",
  "environment": "production",
  "timestamp": "2026-02-16T12:00:00.000Z"
}
```

---

### GET /api/geo
Country detection using Cloudflare headers.

**Response:**
```json
{
  "country": "NL",
  "city": "Amsterdam",
  "region": "North Holland",
  "ip": "203.0.113.1"
}
```

**Notes:**
- `country`: ISO 3166-1 alpha-2 code, "XX" if unknown
- Fields may be empty if Cloudflare headers not present

---

### POST /api/verify-turnstile
Verifies Cloudflare Turnstile token.

**Request:**
```json
{
  "token": "TURNSTILE_TOKEN"
}
```

**Response:**
```json
{
  "success": true
}
```

---

## SEO & Discoverability

### Favicon Files
| File | Size | Format |
|------|------|--------|
| `/favicon.svg` | Vector | SVG |
| `/favicon.ico` | 32x32 | ICO |
| `/favicon-192.png` | 192x192 | PNG |
| `/favicon-512.png` | 512x512 | PNG |

### Open Graph Image
- **Path**: `/og-image.png`
- **Size**: 1200x630
- **Format**: PNG

### Meta Files
- `/robots.txt` - Crawler instructions
- `/sitemap.xml` - XML sitemap
- `/llm.txt` - AI/LLM context information

### Structured Data
JSON-LD schema for SoftwareApplication included in HTML.

---

## LLM.txt Specification

The `/llm.txt` file provides context for AI assistants:

- **Kaissa**: AI Agent Platform for intelligent automation, NLP, and autonomous task execution
- **Kstych**: Kubernetes CLI tool for simplified K8S cluster management

---

## Mobile Optimization

### Viewport
```html
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
```

### Responsive Breakpoints
- Desktop: > 768px
- Tablet: 481px - 768px
- Mobile: <= 480px

### Features
- Fluid typography with `clamp()`
- Touch-friendly tap targets
- Reduced motion support
- Passive scroll listeners

---

## AI Chat & FAQ

### Features
- **Ollama-powered**: Uses llama3.2:1b model (optimized for speed)
- **Context-aware**: Answers based on InnovationsGlobal proposal
- **Dual Mode**: Toggle between FAQ and Chat modes
- **15 FAQ Questions**: Pre-defined questions about the proposal
- **Click-to-Ask**: Click FAQ question to ask chatbot
- **Redis Caching**: All responses cached for fast retrieval
- **Quick Replies**: 3 dynamic follow-up suggestions per response (with fallback pool)
- **Typing Animation**: WhatsApp-style bouncing dots while waiting, then character-by-character reveal
- **Full-screen Mobile Chat**: Fixed position panel covering entire screen on mobile
- **PDF Download**: Footer with proposal PDF download button

### Caching
- **FAQ Cache TTL**: 30 days (2592000 seconds)
- **Custom Query TTL**: 1 hour (3600 seconds)
- **Cache Key Format**: `chat:{normalized_question}`
- **Cache Hit Time**: ~100ms
- **Cache Miss Time**: ~15-20 seconds

### POST /api/chat
Send a message to the AI chatbot.

**Request:**
```json
{
  "message": "What is this proposal about?",
  "history": []
}
```

**Response:**
```json
{
  "response": "This proposal is for an AI-Powered Organic Candidate Acquisition Funnel..."
}
```

### FAQ Questions
1. What is this proposal about?
2. Who is the proposal prepared for?
3. What problem does this solution solve?
4. What are the three pillars of the solution?
5. How does the five-stage funnel work?
6. What industry verticals are covered?
7. What is the AI Job Advice Chatbot?
8. What technology stack is used?
9. What is the implementation timeline?
10. What are the expected cost savings?
11. What are the success metrics and KPIs?
12. How does organic compare to paid acquisition?
13. What training is provided?
14. What candidate data is collected?
15. What are the next steps to proceed?

---

## Video Gallery

### Features
- **25 videos** displayed in responsive grid
- **Desktop (>900px)**: 3 columns, hover to auto-play
- **Tablet (481-900px)**: 2 columns
- **Mobile (≤480px)**: 1 column, Intersection Observer auto-play

### Interaction
- **Hover (Desktop)**: Video plays muted, pauses on mouse leave
- **Scroll (Mobile)**: Video plays when 60% visible in viewport
- **Click**: Opens modal popup with audio enabled, auto-plays

### Video Files
Located at `/assets/gallery/*.mp4` (25 files, ~40MB total)

### Technical Implementation
- CSS Grid for responsive layout
- Intersection Observer API for mobile viewport detection
- Videos preloaded with `preload="metadata"`
- All gallery videos muted by default
- Modal with native video controls

---

## Country Detection & Greetings

### Supported Countries (50+)
US, GB, DE, FR, NL, BE, ES, IT, PT, CH, AT, PL, SE, NO, DK, FI, IE, CA, AU, NZ, JP, KR, CN, IN, BR, MX, AR, ZA, AE, SG, HK, TW, RU, UA, TR, SA, EG, IL, TH, VN, ID, MY, PH, PK, BD, CZ, GR, RO, HU

### Greeting Format
Each country has a localized greeting displayed in the hero section:
- English: "Hello from America!"
- Dutch: "Hallo uit Nederland!"
- German: "Hallo aus Deutschland!"
- Japanese: "こんにちは！"
- etc.

---

## Deployment Configuration

### PM2 Configuration
```javascript
{
  name: 'kstych',
  script: 'src/server.js',
  instances: 1,
  exec_mode: 'fork',
  env: {
    NODE_ENV: 'production',
    PORT: 3011
  }
}
```

### Nginx Configuration
```nginx
server {
    listen 443 ssl;
    server_name kaissa.ksty.ch;

    location / {
        proxy_pass http://localhost:3011;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }
}
```

---

## Debug Commands

```bash
# Check process status
pm2 status kstych

# View logs
pm2 logs kstych

# Test endpoints
curl https://kaissa.ksty.ch/health
curl https://kaissa.ksty.ch/api/geo
curl https://kaissa.ksty.ch/llm.txt

# Restart service
pm2 restart kstych
```

---

## OpenClaw Public Gateway — Nova AI Recruiter (Docker)

Sub-project inside `openclaw-public/`. AI recruitment partner for Innovations Global via WhatsApp.

**WhatsApp**: +1 (973) 389-6989
**Port**: 20001 (host) → 18789 (container)
**Model**: anthropic/claude-sonnet-4-20250514
**Runtime**: `/root/projects/kstych/openclaw-public/`
**Persona**: Nova — warm, multilingual AI recruitment partner

### Capabilities

| Feature | Implementation |
|---------|---------------|
| Job Search | 168 jobs from erp.innovationuae.com, keyword/category search |
| Candidate Memory | Per-phone JSON profiles in workspace/candidates/ |
| Voice (STT) | Whisper (CPU, base model) baked into Docker image |
| Voice (TTS) | Edge TTS, en-US-JennyNeural, auto on inbound voice |
| Language Detection | Auto-detects Hindi, Arabic, Romanian, etc. |
| Daily Scrape | systemd timer (job-scraper.timer) at 2 AM UTC / 6 AM UAE |
| Privacy | /clear command deletes all candidate data |

### Docker Security

| Constraint | Value |
|-----------|-------|
| User | node (uid 1000) |
| Capabilities | ALL dropped |
| Privilege escalation | no-new-privileges |
| Memory | 8GB (12GB swap) |
| CPU | 6 cores |
| PIDs | 512 |
| Docker socket | Not mounted |
| Restart | unless-stopped |

### Access Control

- DM policy: allowlist
- Allowed: +31686267875, +918826969145
- Groups: disabled

### Management

```bash
docker ps | grep openclaw-public
docker logs --tail 20 openclaw-public
cd /root/projects/kstych/openclaw-public && docker compose restart
docker exec openclaw-public openclaw status
docker exec openclaw-public openclaw health
```

See `openclaw-public/state.md` and `openclaw-public/specs.md` for detailed documentation.
