★ ACADEMIC USE · MIL-EDU PROJECT · ATM 2026 ★

IOANAD-WX · TACTICAL WX OPERATIONS

Documentatie tehnica platforma de scenarii meteo pentru simulator C-27J Spartan

Author: Ioana Diaconu  ·  Codename: SPARTAN-MET / IOANAD-WX  ·  Version: 1.0  ·  Date: 2026-05-03
Status: OPERATIONAL BRIEFING-READY

Acest document este manualul tehnic complet al platformei IOANAD-WX (cunoscuta si ca SPARTAN-MET) — sub-componenta web a sistemului de suport-decizie meteo pentru avionul de transport tactic C-27J Spartan, dezvoltat ca proiect academic la Academia Tehnica Militara (ATM) in 2026. Documentul este destinat autoarei (pentru redactarea memoriului de licenta), comisiei (pentru sustinere) si operatorilor (instructori/cursanti) care folosesc platforma in briefing-uri.

📑 Cuprins

  1. Mission & obiective
  2. Arhitectura sistem
  3. Stack tehnologic
  4. Model de date · scenariu WX
  5. Tipuri fenomene meteo
  6. Evolutie temporala & overrides
  7. Mission Planner (Editor WX)
  8. Briefing Replay
  9. API tactical endpoint
  10. Autentificare & securitate
  11. Workflow operational
  12. Integrare cu C-27J Radar (APK)
  13. Integrare cu MATLAB decision engine
  14. Integrare cu ESP32 cabin gateway
  15. Deploy & ops
  16. Structura fisiere proiect
  17. Runbook operator
  18. Troubleshooting
  19. Anexa pentru memoriu licenta
  20. Glosar termeni

🎯 1. Mission & Obiective

Aplicatia IOANAD-WX este o platforma web pentru generarea, distributia si replay-ul scenariilor meteo folosite ca input in simularea zborurilor tactice C-27J. Misiunea ei este sa asigure un "single source of truth" pentru un scenariu meteo, accesibil in mod identic de:

📱

C-27J Radar (APK)

Aplicatia Android pe tableta in cabina — descarca scenariul, evalueaza vremea la pozitia GPS curenta, trimite output catre ESP32 si MATLAB.

CONSUMER · token read-only
🖥

MATLAB Decision Engine

Engine-ul impus de profesor — citeste GPS de la ESP32, evalueaza scenariul si recomandarea de zbor (NORMAL/DEV/DIVERT/GO-AROUND).

CONSUMER · token read-only
🛠

Operator (instructor)

Editeaza scenariul in browser pe pagina /editor/, salveaza pe server. Modificarea este vizibila imediat de toate consumerele.

PRODUCER · Basic Auth
📺

Briefing Replay

Player TV-style pentru proiector in sala de briefing si AAR (After Action Review).

VIEWER · public

Obiective masurabile

ObiectivMetricaTarget
Latenta editor → APKsecunde de la save la fetch reusit< 3 s
Capacitate scenariinumar fenomene WX simultane intr-un scenariu≥ 30
Durata scenariusecunde simulate60 ÷ 14 400 s (4 h)
Auth API endpointtoken hex 32 caractere min≥ 32
Rate limitrequest-uri pe minut per token+IP120/min
PersistentaJSON pe disc, atomic write0 corruptie la crash

📡 2. Arhitectura sistem

Sistemul are trei niveluri: web (IOANAD-WX), tactical edge (APK + ESP32 + GPS), decision (MATLAB).

[INTERNET / WIFI SALA] │ ▼ ┌──────────────────────────────────────────┐ │ IOANAD.MENSOFT.RO (web · PHP 7.1+) │ <-- THIS PLATFORM │ ┌────────────┐ ┌─────────────────┐ │ │ │ index.php │ │ /editor/ Basic │ │ │ │ landing │ │ Auth ioana/*** │ │ │ └─────┬──────┘ └────────┬────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌────────────────────────────────┐ │ │ │ /scenarios/wx/*.json (disk) │ │ │ │ /scenarios/flight/*.json │ │ │ │ /scenarios/_audit.log │ │ │ └──────────────┬─────────────────┘ │ │ │ │ │ ┌──────────────▼─────────────────┐ │ │ │ /api/endpoint.php │ │ │ │ - token auth (X-Auth-Token) │ │ │ │ - rate limit 120/min │ │ │ │ - actions: ping/list/get │ │ │ └──────────────┬─────────────────┘ │ └──────────────────┼─────────────────────────┘ │ HTTPS + token ┌──────────────┼──────────────┐ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ 📱 C-27J Radar │ │ 🖥 MATLAB engine │ │ (Android tablet)│ │ decision tree │ │ replay/remote │ │ webread + parse │ └─────────┬───────┘ └────────┬─────────┘ │ POST /advice │ webread /gps │ (OWM + METAR) │ ▼ ▲ ┌─────────────────────────────────┐ │ 📡 ESP32 cabin gateway │ │ /gps · /advice · /display │ └─────────────────────────────────┘ ▲ │ NMEA / fake GPS ┌───────────┴────────────┐ │ GPS BT Holux (real) │ │ Sim Arduino UART2 │ │ Replay SPIFFS NMEA │ └────────────────────────┘

Principii arhitecturale

⚙ 3. Stack tehnologic

LayerTehnologieRol
HostingApache 2.4 + mod_rewrite + mod_auth_basicHTTPS terminator, autentificare Basic, rewrites
BackendPHP 7.1+ (compatibil pana la 8.2)Endpoint API, editor, replay player
PersistentaFisiere JSON pe discNiciun database server — portabil, backup simplu (tar)
Frontend editorLeaflet 1.9 + Leaflet.draw + Vanilla JSHarta interactiva, desenare obiecte WX
Frontend replayLeaflet 1.9 + Vanilla JS (read-only)Animatie scenariu, time-bar, viteza variabila
Auth (editor)HTTP Basic + bcrypt (.ht_ioanad)Producer-only zone
Auth (API)Token fix (32+ hex) in config.phpConsumer (APK/MATLAB)
AuditAppend-only log fileConformitate & debugging

De ce nu MySQL/PostgreSQL

Pentru un proiect academic cu < 100 scenarii pe disc si concurenta minima (un singur instructor scrie odata), JSON pe disc + atomic rename ofera:

Trade-off: nu se scaleaza la > 1000 scenarii sau editari concurente. Pentru un proiect didactic e ideal.

📋 4. Model de date — scenariu WX

Un scenariu meteo este un fisier JSON in /scenarios/wx/<id>.json. Schema (schema_version: 2):

{
  "id":          "wx_real_ro_20240613",          // unic, [A-Za-z0-9_-]{1,64}
  "type":        "wx",
  "name":        "Eveniment real 13/06/2024 — Outbreak supercele V→E",
  "schema":      2,
  "version":     1,                              // bump la fiecare save
  "created":     "2026-05-03T10:00:00+00:00",
  "modified":    "2026-05-03T10:00:00+00:00",
  "modified_by": "ioana",
  "scenario": {
    "duration_s": 28800,                         // 8h simulate
    "wx_objects": [
      {
        "id":      "cb_drobeta_mehedinti",       // unic in scenariu
        "type":    "CB",                         // vezi sectiunea 5
        "label":   "Supercell Drobeta-T.Severin",
        "t_start": 600,                          // s de la t=0
        "t_end":   5400,                         // null = pana la final
        "geom": {
          "center":       [44.63, 22.66],         // [lat, lon] WGS84
          "radius_nm":    7,
          "top_ft":       45000,
          "intensity_pct": 95
        },
        "evolution": {
          "motion": {"dir_deg": 80, "speed_kt": 26},
          "rates":  {"radius_nm": 1, "top_ft": -500, "intensity_pct": -8}
        },
        "overrides": [
          {"t": 1800, "geom": {"intensity_pct": 98}},
          {"t": 4200, "geom": {"intensity_pct": 70}}
        ]
      }
      // … alte fenomene
    ]
  }
}

Camp cu camp

CampTipMandatorySemnificatie
idstringDAIdentificator unic, regex ^[A-Za-z0-9_-]{1,64}$. Deveine numele fisierului.
type"wx"DADiscriminator pentru API (alaturi de flight, mission).
namestringrecomandatEticheta umana (max 100 caractere).
schemaintDAVersiune model — actual 2. Cresterea = breaking change.
versionintDABumped la fiecare save. Util pentru detect "scenariu schimbat" la consumer.
scenario.duration_sintDATotal secunde simulate. Actuall 60 ÷ 14400 (4h max).
scenario.wx_objects[]arrayDALista de fenomene. Vezi sectiunea 5.

⛈ 5. Tipuri fenomene meteo

Definitiile sunt in assets/wx_types.json. Pentru fiecare tip se specifica shape (cell / polygon / line), geom_defaults, evolution_defaults si rank (prioritate vizuala).

CodNumeShapeIconGeom defaultDefault motionRank
CBCumulonimbus / Thunderstormcellr=8nm, top=35kft, 100%270°/25kt, intens -15%/h100
SQUALLSquall lineline🌬w=2nm, 90%90°/30kt90
FRONT_CCold frontlinew=5nm, 80%90°/18kt80
FRONT_WWarm frontlinew=8nm, 60%60°/12kt40
ICEIcing areapolygon🧊top=18kft, base=6kft, 70%270°/20kt70
TURBTurbulencepolygon🌀top/base/intensvariabil60
WSWind shearcellr=3nm, 80%variabil50
FOGCeata / vizibilitate redusapolygon🌫top=800ft, 70%0°/0kt (statica)30

Shape-uri si campuri geometrice

🟠

cell (CB, WS)

"geom": {
  "center": [lat, lon],
  "radius_nm":    <float>,
  "top_ft":       <int>,
  "intensity_pct":<0..100>
}
🟢

polygon (ICE, TURB, FOG)

"geom": {
  "points": [[lat,lon], …],
  "top_ft":       <int>,
  "base_ft":      <int>,
  "intensity_pct":<0..100>
}
🟦

line (SQUALL, FRONT_*)

"geom": {
  "points": [[lat,lon], …],
  "width_nm":     <float>,
  "intensity_pct":<0..100>
}

⏳ 6. Evolutie temporala & overrides

Un fenomen are 3 surse de evolutie aplicate in ordine (composition rule):

  1. Geometrie initiala (geom) — la t = t_start.
  2. Rates auto (evolution.motion + evolution.rates) — interpolare liniara intre snap-uri.
  3. Overrides (overrides[]) — snap-uri forțate la momente t specifice; sterg rate-urile pana la urmatorul snap.

Algoritm de evaluare la moment t

function evaluate(obj, t) {
  if (t < obj.t_start) return null;                   // inca nu exista
  if (obj.t_end !== null && t > obj.t_end) return null; // a expirat

  // 1) start cu geometria initiala
  let geom = clone(obj.geom);

  // 2) determina ultimul override aplicabil
  let prev_t = obj.t_start;
  let prev_geom = clone(obj.geom);
  for (const ov of (obj.overrides || [])) {
    if (ov.t <= t) { prev_t = ov.t; prev_geom = merge(prev_geom, ov.geom); }
    else break;
  }

  // 3) aplica rates intre prev_t si t
  const dt_h = (t - prev_t) / 3600;
  if (geom.center)   geom.center = move(geom.center, motion, dt_h);
  if (geom.points)   geom.points = geom.points.map(p => move(p, motion, dt_h));
  if (geom.radius_nm)     geom.radius_nm     += rates.radius_nm * dt_h;
  if (geom.top_ft)        geom.top_ft        += rates.top_ft * dt_h;
  if (geom.intensity_pct) geom.intensity_pct = clamp(geom.intensity_pct + rates.intensity_pct * dt_h, 0, 100);

  return geom;
}

De ce overrides in plus fata de rates

Rates capteaza evolutia "naturala" continua (front se misca constant, intensitatea scade). Overrides capteaza evenimente discrete: "la t=1800 supercelula explodează la 98%" sau "la t=4200 se disipează la 70%". Combinatia permite scenarii bogate fara cod custom per scenariu.

Exemplu vizual de evolutie

t=0           t=600        t=1800        t=4200       t=5400
│             │            │             │            │
○ creat       ●● 95%       ●●● 98%       ●● 70%       × disipat
              ↑            ↑             ↑            ↑
              t_start    override #1   override #2  t_end
              radius=7    intensity=98  intensity=70  end
              (din geom)  (forced)     (forced)     (cleanup)
              ↓ rates intre snap-uri:
              radius +1 nm/h, top -500 ft/h, intensity -8%/h

🛠 7. Mission Planner (Editor WX)

Editor accesibil la https://ioanad.mensoft.ro/editor/ dupa autentificare HTTP Basic (user ioana, parola in .ht_ioanad bcrypt).

Layout pagina

┌─────────────────────────────────────────────────────────────┐
│  TOPBAR: nume scenariu | id | [Nou] [Save] [Load] [JSON]   │
├──────────────┬──────────────────────────────────────────────┤
│  PANEL STG.  │                                              │
│              │                                              │
│  Durata sim. │           HARTA LEAFLET                      │
│  [_____] s   │           (RO + vecini)                      │
│              │                                              │
│  Tipuri WX   │           - desenare cell (click)            │
│  ⛈ CB        │           - desenare polygon (Leaflet draw)  │
│  🌬 SQUALL    │           - desenare line                   │
│  ❄ FRONT_C   │                                              │
│  🌫 FOG       │                                              │
│  …           │                                              │
│              │                                              │
│  Lista WX    │                                              │
│  ☐ obj1 ⛈    │                                              │
│  ☐ obj2 🌫    ├──────────────────────────────────────────────┤
│  …           │  TIME-BAR:  ▶  [====•=========]  t=600s     │
│              │             viteza ×10 ▼                     │
└──────────────┴──────────────────────────────────────────────┘

Flow operator: creeaza scenariu nou

  1. Click 📄 Nou — se goleste canvas-ul si lista.
  2. In topbar, set id (ex: WX_TS_BUC_DEMO) si nume descriptiv.
  3. In panel stanga, set durata simulare (ex: 1800 s = 30 min).
  4. Click pe un tip WX (ex: ⛈ CB) → cursorul devine "+", click pe harta unde plasezi cella.
  5. Pe lista din stanga apare obiectul. Click pe el deschide panel-ul de editare:
    • Geometrie: raza, varf, intensitate
    • Evolutie: directie + viteza miscare, rate intensitate, rate raza
    • Overrides: + adauga override la moment t cu modificari forțate
    • t_start, t_end
  6. Repeti pentru toate fenomenele.
  7. Apesi ▶ Play in time-bar pentru preview animat — vezi cum se misca/intensifica fenomenele.
  8. Cand esti multumita, click 💾 Save → POST /api/save.php → JSON pe disc.

API folosit de editor (intern)

EndpointMethodAuthBody / QueryResponse
/api/save.phpPOSTBasicJSON scenariu complet{ok:true, version:N}
/api/load.php?id=X&type=wxGETBasicJSON scenariu
/api/list.php?type=wxGETBasic{scenarios:[…]}
/api/delete.phpPOSTBasic{id:"X",type:"wx"}{ok:true}

📺 8. Briefing Replay

Replay player accesibil la https://ioanad.mensoft.ro/editor/play.php sau direct cu parametru ?id=<scenario>. Scopul: prezentare in sala de briefing sau AAR (After Action Review) dupa misiune.

Caracteristici

Caz de utilizare 1 — Briefing pre-misiune

  1. Instructorul deschide play.php?id=WX_REAL_RO_20240613 pe laptop conectat la proiector.
  2. Apesi la viteza ×30 → 8h simulate in ~16 min reale.
  3. Cursantii observa cum se dezvolta supercelele V→E peste tara.
  4. Pauza la momente cheie: "aici ce decizie iei daca esti FL080 deasupra Olteniei?"
  5. La final: deschidem APK pe tableta cu acelasi scenariu — verificam ca calculele coincid.

Caz de utilizare 2 — AAR debrief

  1. Dupa misiunea simulata in MATLAB, MATLAB exporta log GPS + decisii.
  2. Replay player rulează scenariul WX in paralel cu track-ul GPS suprapus.
  3. Comisia vede unde a deviat avionul si compara cu pozitia fenomenelor.
  4. Discutie: "de ce a virat la dreapta in loc de stanga?" — raspuns vizibil pe harta.

🛰 9. API tactical endpoint

Endpoint-ul public pentru consumere (APK + MATLAB):

GET https://ioanad.mensoft.ro/api/endpoint.php

Parametri comuni

ParametruSursaMandatoryExemplu
tokenquery string sau header X-Auth-TokenDAa1b2c3...
actionqueryDAping|list|get
typequeryla list/getwx
idqueryla getwx_real_ro_20240613

Action: ping

GET /api/endpoint.php?token=<APK_TOKEN_HEX>&action=ping

200 OK
{
  "ok":          true,
  "server_time": "2026-05-03T13:45:12+00:00",
  "who":         "apk_c27j_v1",
  "rate_used":   3,
  "rate_max":    120
}

Action: list

GET /api/endpoint.php?token=<APK_TOKEN_HEX>&action=list&type=wx

200 OK
{
  "count": 2,
  "scenarios": [
    {
      "id":         "wx_real_ro_20240613",
      "type":       "wx",
      "name":       "Outbreak supercele V→E Romania",
      "version":    1,
      "modified":   "2026-05-03T10:00:00+00:00",
      "duration_s": 28800,
      "wx_count":   12
    },
    {
      "id":         "wx_real_derecho_20220817",
      "type":       "wx",
      "name":       "Derecho Europa Centrala 17/08/2022",
      "version":    1,
      "modified":   "2026-05-03T10:30:00+00:00",
      "duration_s": 21600,
      "wx_count":   8
    }
  ]
}

Action: get

GET /api/endpoint.php?token=<APK_TOKEN_HEX>&action=get&type=wx&id=wx_real_ro_20240613

200 OK
{
  "id":      "wx_real_ro_20240613",
  "type":    "wx",
  "name":    "…",
  "schema":  2,
  "version": 1,
  "scenario": { "duration_s": 28800, "wx_objects": [...] }
}

Coduri eroare

HTTPerrorCauzaRemedy
400invalid typetype ≠ wx|flight|missionverifica parametru
400invalid idid contine caractere ne-permiseregex ^[A-Za-z0-9_-]{1,64}$
400unknown actionaction ≠ ping|list|getvezi sectiunea 9
401missing tokennu s-a trimis tokenadauga ?token=… sau header
403invalid tokentoken nu se potrivestecere unul nou de la admin
404not foundscenariu inexistentverifica list mai intai
405method not allowedPOST in loc de GETfoloseste GET
429rate limit exceeded>120 cereri/min/IPasteapta 60 s
500server misconfiguredconfig.php lipsa/coruptcontact admin

🔐 10. Autentificare & securitate

Doua zone, doua mecanisme

ZonaURLMecanismStorage credentiale
Producer (operator)/editor/* + /api/save|load|list|delete.phpHTTP Basic + bcrypt.ht_ioanad
Consumer (APK/MATLAB)/api/endpoint.phpToken fix in query/headerconfig.php (NU in git)
Public viewer/ + /editor/play.phpNone

Storage tokeni — config.php

<?php
return array(
    'tokens' => array(
        'apk_c27j_v1'    => '<APK_TOKEN_HEX>',     // 32+ hex chars
        'matlab_c27j_v1' => '<MATLAB_TOKEN_HEX>',
    ),
    'rate_limit_per_min' => 120,
);

Reguli stricte tokens

Rate limiting

Implementat in endpoint.php cu fisiere temporare per (token_alias, IP) in sys_get_temp_dir()/ioanad_rl/. Fereastra fixa de 60 s, contor incremental, reset cand timestamp-ul depaseste 60 s. La depasire: HTTP 429.

Audit log

/scenarios/_audit.log

[2026-05-03T13:45:12+00:00] ? | 192.168.168.103 | endpoint_list | apk_c27j_v1 type=wx count=2
[2026-05-03T13:45:18+00:00] ? | 192.168.168.103 | endpoint_get  | apk_c27j_v1 type=wx id=wx_real_ro_20240613 v=1
[2026-05-03T13:46:01+00:00] ? | 5.14.163.55     | endpoint_auth_fail | token_prefix=deadbe... ip=5.14.163.55
[2026-05-03T13:50:22+00:00] ioana | 192.168.168.103 | scenario_save | id=WX_TS_BUC_DEMO type=wx version=3

Headers HTTP de securitate

HTTPS obligatoriu

.htaccess redirectioneaza orice HTTP → HTTPS cu 301:

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

🪖 11. Workflow operational

De la "vreau sa fac un briefing" la "avionul a aterizat in MATLAB":

T-2h PRE-MISSION (instructor pe laptop) ─────────────────────────────────────────────────────────────── 1. Login HTTP Basic la /editor/ 2. New scenario, plaseaza CB/ICE/FRONT pe harta RO 3. Set durata 1800s, evolutie automata + 2-3 overrides 4. Save → /scenarios/wx/WX_TS_BUC_DEMO.json (atomic) 5. Preview cu Play in editor — verifica vizual T-30m PRE-FLIGHT (operator + cursant) ─────────────────────────────────────────────────────────────── 6. Tableta APK conectata la WiFi sala 7. Tap "Replay → Remote" → fetch list la endpoint 8. Tap pe scenariul dorit → fetch get → cache local 9. APK display: harta cu fenomenele initiale (t=0) T-0 MISSION START ─────────────────────────────────────────────────────────────── 10. MATLAB porneste decision tree, asculta ESP32 /gps 11. ESP32 alimentat, conectat la WiFi sala 12. APK switch la "Apply/Run" → pull GPS de la ESP32 13. APK calcul WX la (lat,lon,t) → POST /advice JSON 14. ESP32 propaga catre MATLAB 15. MATLAB decisie: NORMAL / DEV / DIVERT / GO-AROUND T+30m DEBRIEF (proiector) ─────────────────────────────────────────────────────────────── 16. Replay player play.php?id=WX_TS_BUC_DEMO ×30 viteza 17. MATLAB log GPS suprapus → discutie comisie

Cine atinge ce

RolAtingeNu atinge
InstructorEditor (creeaza/modifica), Replay playerAPI tokens (le primeste, nu le genereaza)
Cursant operatorAPK pe tabletaEditor (read-only via Replay)
Pilot simulatorMATLAB UIAPI direct (MATLAB face apelurile)
Admin sistemconfig.php, deploy, certificateContinut scenarii (nu intervine)
ComisiaReplay player la AARNimic altceva

📱 12. Integrare cu C-27J Radar (APK)

C-27J Radar este aplicatia Android (numele real al pachetului — anonimizat in document) care ruleaza pe tableta in cabina. Ea consuma scenariile WX din IOANAD-WX si trimite output catre ESP32 + MATLAB.

Sectiunea Replay → Remote in APK

In APK exista un panou Replay cu doua taburi:

Pseudocod fetch in Kotlin (anonimizat)

// package ro.aviation.c27jradar.debug
// (numele real al pachetului — anonimizat in document)
class IoanadWxClient(private val baseUrl: String, private val token: String) {

    fun listScenarios(): List<ScenarioInfo> {
        val url = "$baseUrl/api/endpoint.php?token=$token&action=list&type=wx"
        val resp = httpGet(url, headers = mapOf("X-Auth-Token" to token))
        if (resp.code == 429) throw RateLimitException(resp.body)
        if (resp.code in 400..499) throw AuthException("API: ${resp.body}")
        val json = JSONObject(resp.body)
        return json.getJSONArray("scenarios").mapToList { ScenarioInfo(it) }
    }

    fun getScenario(id: String): WxScenario {
        val url = "$baseUrl/api/endpoint.php?token=$token&action=get&type=wx&id=$id"
        val resp = httpGet(url)
        return WxScenario.parse(resp.body)
    }
}

// Apoi in flow-ul Apply/Run:
val scenario = client.getScenario("wx_real_ro_20240613")
val timer = scheduleAtFixedRate(period = 5_000L) {
    val gps = espClient.fetchGps()         // GET /gps de la ESP32
    val wxNow = scenario.evaluate(gps.t, gps.lat, gps.lon)
    val advice = AdvicePayload(gps, wxNow)
    espClient.postAdvice(advice)            // POST /advice la ESP32
}

Caching in APK

🖥 13. Integrare cu MATLAB decision engine

MATLAB este "creierul" sistemului (impus de profesor) — citeste GPS de la ESP32, evalueaza scenariul si ia decizii.

Cod MATLAB pentru fetch scenariu

% +io/fetchWxScenario.m
function sc = fetchWxScenario(id)
    base   = 'https://ioanad.mensoft.ro/api/endpoint.php';
    token  = getenv('IOANAD_MATLAB_TOKEN');   % NU hardcoded
    if isempty(token)
        error('Missing env IOANAD_MATLAB_TOKEN');
    end
    opts = weboptions('HeaderFields', {'X-Auth-Token', token}, ...
                      'Timeout', 10, ...
                      'ContentType', 'json');
    url  = sprintf('%s?action=get&type=wx&id=%s', base, id);
    sc   = webread(url, opts);
end

% +io/listWxScenarios.m
function out = listWxScenarios()
    base  = 'https://ioanad.mensoft.ro/api/endpoint.php';
    token = getenv('IOANAD_MATLAB_TOKEN');
    opts  = weboptions('HeaderFields', {'X-Auth-Token', token});
    j     = webread([base '?action=list&type=wx'], opts);
    out   = j.scenarios;
end

Decision tree dupa fetch WX

% main.m (pseudo)
sc = io.fetchWxScenario('wx_real_ro_20240613');

while running
    gps = io.getEspGps();                          % webread ESP32 /gps
    [wx_now, severity] = calc.evaluateAt(sc, gps.t, gps.lat, gps.lon);
    metrics = calc.computeMetrics(gps, wx_now);    % XWC, F-factor, CIP, EDR
    [scenarioId, recommendation] = rules.decide(metrics);
    io.sendEsp(scenarioId, recommendation);        % TCP la ESP32 display
    pause(0.2);
end

Cache local + fallback offline

MATLAB salveaza fiecare get in data/wx_cache/<id>.json cu timestamp. Daca webread da timeout (sala fara internet), incarca din cache si afiseaza warning vizibil in App Designer.

🪛 14. Integrare cu ESP32 cabin gateway

ESP32 este relay-ul intre APK si MATLAB. Important de inteles: ESP32 NU acceseaza direct ioanad.mensoft.ro (resursa de RAM limitata, certificat HTTPS pe device complica viata). APK face fetch din IOANAD-WX si trimite output procesat catre ESP32 prin /advice JSON local.

Endpoint-uri ESP32 (recap din spec proiect)

EndpointMethodSursaContinut
/gpsGEToricine in WiFi localJSON cu lat,lon,t,fix
/advicePOSTAPKJSON cu OWM + METAR + WX-now (din scenariu IOANAD)
/displayPOSTMATLABJSON cu scenariu de afisat pe TFT (severity, recomandare)
/setgpsstartPOSTMATLABfake GPS pentru replay (lat,lon,heading,speed)

De ce APK e intermediar in fluxul WX

🛬 15. Deploy & ops

Cerinte server

Procedura deploy initial

# 1) Upload fisiere
scp -r ioanad_mensoft/ user@host:/var/www/

# 2) Permisiuni
ssh user@host
cd /var/www/ioanad_mensoft
sudo chown -R apache:apache scenarios/
sudo chmod 750 scenarios/
sudo chmod 750 scenarios/wx scenarios/flight scenarios/mission
sudo chmod 644 .htaccess .ht_ioanad

# 3) Config tokeni
cd api/
cp config.example.php config.php
nano config.php
# inlocuieste <APK_TOKEN_HEX> cu output-ul lui:
#   openssl rand -hex 32
sudo chmod 640 config.php
sudo chown root:apache config.php

# 4) VirtualHost Apache
sudo nano /etc/httpd/conf.d/ioanad.conf
<VirtualHost *:443>
    ServerName ioanad.mensoft.ro
    DocumentRoot /var/www/ioanad_mensoft
    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/ioanad.mensoft.ro/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ioanad.mensoft.ro/privkey.pem

    <Directory /var/www/ioanad_mensoft>
        AllowOverride All
        Require all granted
    </Directory>

    # Editor: Basic Auth
    <Directory /var/www/ioanad_mensoft/editor>
        AuthType Basic
        AuthName "IOANAD-WX Operator"
        AuthUserFile /var/www/ioanad_mensoft/.ht_ioanad
        Require valid-user
    </Directory>

    # API write endpoints: Basic Auth
    <FilesMatch "^(save|load|list|delete)\.php$">
        AuthType Basic
        AuthName "IOANAD-WX Operator"
        AuthUserFile /var/www/ioanad_mensoft/.ht_ioanad
        Require valid-user
    </FilesMatch>

    # endpoint.php: NU cere Basic Auth (token in query)
    <Files endpoint.php>
        Satisfy Any
        Allow from all
    </Files>
</VirtualHost>

# 5) Reload
sudo apachectl configtest && sudo systemctl reload httpd

# 6) Test rapid
curl -k https://ioanad.mensoft.ro/api/endpoint.php?token=<APK_TOKEN>&action=ping
# expect: {"ok":true,"server_time":"...","who":"apk_c27j_v1",...}

Schimbare parola operator

htpasswd -B /var/www/ioanad_mensoft/.ht_ioanad ioana
# (-B = bcrypt; introduce parola noua de doua ori)

Backup

# cron pe server (zilnic la 03:00)
0 3 * * * tar czf /backup/ioanad-$(date +\%Y\%m\%d).tgz \
            /var/www/ioanad_mensoft/scenarios \
            /var/www/ioanad_mensoft/api/config.php \
            /var/www/ioanad_mensoft/.ht_ioanad

Monitoring

📂 16. Structura fisiere proiect

ioanad_mensoft/
├── index.php                 landing page (tema militara, dashboard module)
├── .htaccess                 HTTPS redirect, blocheaza .md/.log/.bak
├── .ht_ioanad                bcrypt hash pentru "ioana"
│
├── assets/
│   ├── theme_military.css    tema vizuala comuna
│   ├── airports.json         29 aerodromuri RO + vecini (LR* / LB* / LU* / LH* …)
│   └── wx_types.json         8 tipuri WX cu defaults
│
├── api/
│   ├── _lib.php              helpers comun: resp_json, scenario_path, atomic_write
│   ├── config.example.php    sablon tokeni
│   ├── config.php            (NU in git) tokeni reali
│   ├── endpoint.php          PUBLIC — read-only consumer (APK/MATLAB)
│   ├── list.php              Basic Auth — listare pentru editor
│   ├── load.php              Basic Auth — load scenariu
│   ├── save.php              Basic Auth — save (atomic write)
│   └── delete.php            Basic Auth — delete scenariu
│
├── editor/
│   ├── index.php             dashboard editor cu carduri module
│   ├── weather.php           Mission Planner — editor WX
│   ├── flight.php            Route Editor (WIP)
│   ├── play.php              Briefing Replay player
│   ├── editor.css            stiluri editor (panel-uri, time-bar)
│   ├── play.js               logica animatie replay
│   └── weather.js            logica editor WX (Leaflet draw, evolutie)
│
├── scenarios/
│   ├── wx/                   *.json scenarii meteo
│   │   ├── wx_real_ro_20240613.json
│   │   └── wx_real_derecho_20220817.json
│   ├── flight/               *.json rute zbor (WIP)
│   ├── mission/              *.json scenarii compuse (wx + flight + tasks)
│   └── _audit.log            audit trail (append-only)
│
├── docs/
│   └── index.html            ACEST DOCUMENT (manual tehnic)
│
└── lib/                      placeholder pentru librarii viitoare

📕 17. Runbook operator

Sarcina A: creezi scenariu nou pentru briefing

  1. Browser → https://ioanad.mensoft.ro/editor/
  2. Login: ioana / parola
  3. Click ⛈ WX Editor
  4. In topbar: 📄 Nou; set id + nume
  5. Stanga: set durata simulare
  6. Click pe tip WX (ex: ⛈ CB) → click pe harta → set proprietati
  7. Repeti pentru fiecare fenomen
  8. ▶ Play in time-bar pentru preview
  9. 💾 Save
  10. Verificare: deschide alta fila → /editor/play.php?id=NUME → vezi scenariul live

Sarcina B: distribui token APK la cursant

  1. SSH ca admin pe server
  2. cat /var/www/ioanad_mensoft/api/config.php | grep apk_c27j
  3. Notezi token-ul pe foaie sau USB
  4. Pe tableta cursant, deschide APK → Settings → IOANAD endpoint → paste token
  5. Test: in APK tap Replay → Remote → Refresh → daca apare lista, OK
  6. Niciodata token prin email/Slack

Sarcina C: revoca un token compromis

  1. SSH server
  2. sudo nano /var/www/ioanad_mensoft/api/config.php
  3. Sterge linia cu token-ul compromis sau inlocuieste cu valoare random noua
  4. Salveaza
  5. Notifica APK + MATLAB cu noul token (manual)
  6. Verifica audit log: grep auth_fail /var/www/ioanad_mensoft/scenarios/_audit.log | tail -50

Sarcina D: import scenariu existent (din JSON brut)

  1. Editor → 📂 Load nu e ce vrei (cere ID existent)
  2. Solutie: scp scenariul.json server:/var/www/ioanad_mensoft/scenarios/wx/
  3. Set chown apache:apache + chmod 640
  4. Reincarca editor → apare in lista
  5. Sau direct: foloseste in API get dupa ce-a fost copiat manual

🚨 18. Troubleshooting

SimptomCauza probabilaRezolvare
HTTP 401 la endpoint cu token corectApache adaugă Basic Auth peste endpoint.phpVerifica VHost: endpoint.php trebuie cu Satisfy Any sau in afara FilesMatch
HTTP 500 la savePermisiune scriere pe /scenarios/wx/chown -R apache:apache scenarios; chmod 750
JSON corupt dupa saveDisc plin — atomic write esueazadf -h; sterge backup-uri vechi; reincearca
APK primeste 429 frecventPolling prea agresivIn APK: cresterea intervalului fetch list la 60 s; get doar la schimb scenariu
Editor nu salveaza, console JS arata 401Sesiune Basic expirataRefresh pagina, reintroducere parola
Replay player gol pentru un scenariuSchema scenariu < 2 sau JSON invalidjq . /var/www/.../scenariu.json — verificare sintaxa
Time-bar nu se misca in previewJS eroare in weather.jsF12 console → fixezi obiect cu geom incomplet
MATLAB webread timeoutWiFi sala blocheaza HTTPS sau proxyAlternativ hotspot mobil; sau MATLAB cu weboptions('Proxy',...)
Audit log creste prea repedeBot scaneaza endpointLog rotation + fail2ban regula pe HTTP 403/401 repetat
Scenariul "dispare" din lista dupa saveid duplicat, suprascrisVerifica scenario.modified; backup zilnic recupereaza

Comenzi diagnostic rapide

# API health
curl -k "https://ioanad.mensoft.ro/api/endpoint.php?token=XXX&action=ping"

# Listare scenarii din shell
curl -k "https://ioanad.mensoft.ro/api/endpoint.php?token=XXX&action=list&type=wx" | jq .

# Verifica permisiuni
ls -la /var/www/ioanad_mensoft/scenarios/wx/

# Ultimele eroari API
tail -100 /var/www/ioanad_mensoft/scenarios/_audit.log | grep -E "fail|err"

# Apache error log
sudo tail -200 /var/log/httpd/error_log | grep ioanad

# Stress test endpoint (verificare rate limit)
ab -n 200 -c 10 "https://ioanad.mensoft.ro/api/endpoint.php?token=XXX&action=ping"

🎖 19. Anexa pentru memoriul de licenta

Aceasta sectiune este destinata explicit pentru citarea in memoriu si maparea pe cerintele profesorului.

Maparea pe capitole 2.x / 3.x cerute

Capitol cerutAcoperire IOANAD-WXSectiuni din acest doc
2.1 Rolul informatiilor meteoWX scenario ca date primare; ARINC-661 conformity (intentie)§1, §11
2.3.2 Surse meteoIOANAD-WX = sursa simulata cu evolutie deterministica§4, §5, §6
2.3.3 AlgoritmEvaluation function: rate-uri liniare + overrides; rule engine MATLAB consuma§6, §13
2.3.4 Cele 5 scenarii canoniceSalvate ca scenarii distincte in /scenarios/wx/ (S0..S4)§4, §17
2.3.5 Interfata2 TFT pe ESP32 = consumer; APK = producer pentru ESP32§14
2.4 Erori si limitariLatenta API (<3 s observat), schema versionare, rate limit§1, §10
2.5 ConcluziiSistem suport-decizie, audit log, separare producer/consumer§1, §11, §15
3.1-3.4 Lucrari graficeDiagrame ASCII din §2, screenshots editor + replay player§2, §7, §8

Contributii originale (claim pentru sustinere)

Limitari recunoscute (declarat in memoriu, NU ascuns)

Bibliografie sugerata pentru citare

🛫 20. Glosar termeni

AAR (After Action Review)
Sedinta de debrief post-misiune in care echipa analizeaza decisii si invata din execuție.
APK
Pachet de instalare Android (Android Package). In contextul nostru = aplicatia C-27J Radar pe tableta.
ARINC 661
Standard ARINC pentru sistemele de display in cockpit comercial. Reglementeaza format CDS (Cockpit Display System).
ATM
Academia Tehnica Militara din Bucuresti (institutia de invatamant a autoarei).
Basic Auth
Mecanism HTTP de autentificare cu user+parola in header (RFC 7617). Folosit pentru zona producer.
bcrypt
Functie de hash pentru parole, rezistent la brute-force prin cost factor adjustabil. Folosit in .ht_ioanad.
CB
Cumulonimbus — nor de furtuna cu dezvoltare verticala mare; risc grindina, fulgere, turbulenta severa.
CIP (Current Icing Potential)
Algoritm Bernstein 2005 pentru evaluare risc giurgiu pe categorie 0..4.
EDR (Eddy Dissipation Rate)
Metrica turbulentei standardizata ICAO; m^(2/3)/s.
F-factor
Metrica NASA Bowles pentru wind shear pe glide slope; F = (1/g)·(dUx/dt) − w/Va; threshold 0.105.
FRONT_C / FRONT_W
Front rece / front cald in modelul de scenariu.
HTTP Basic Auth
vezi Basic Auth.
ICAO
International Civil Aviation Organization. Reglementeaza standarde aviatie civila.
IOANAD-WX
Codename platformei web (acest sistem). Compus din "Ioana D." + "WX". Alias: SPARTAN-MET.
METAR
Meteorological Aerodrome Report. Raport meteo standardizat la sol, format ICAO.
NMEA
Standard pentru formate sentence GPS (GPRMC, GPGGA etc.). Folosit pentru replay GPS pe ESP32.
OWM
OpenWeatherMap — sursa optionala de meteo real, alternativa la AviationWeather.gov.
SIGMET
Significant Meteorological Information. Avertizari meteo critice pentru aviatie.
SPARTAN-MET
vezi IOANAD-WX. Codename folosit in index.php pentru landing.
TAF
Terminal Aerodrome Forecast. Prognoza meteo pentru aerodrom.
Token
Sir hex de 32+ caractere folosit pentru autentificare API. Comparat cu hash_equals() (constant-time).
WX
Abreviere standard "Weather" in aviatie. Folosit ca prefix in tot codul (wx_objects, wx_types).
XWC (Crosswind Component)
Componenta vant transversala fata de pista. XWC = |V·sin(wind_dir − rwy_hdg)|.

🎯 Note finale pentru autoare

✅ Definition of Done