{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://mappify.se/scopefile.schema.json",
  "title": "Mappify ScopeFile v0.2",
  "description": "Kanoniskt format för Mappify-processkartor. Semantik separerad från layout.",
  "type": "object",
  "required": [
    "schemaVersion",
    "id",
    "name",
    "domain"
  ],
  "properties": {
    "schemaVersion": {
      "type": "string",
      "const": "0.2"
    },
    "id": {
      "type": "string",
      "description": "Unikt ID för kartan, t.ex. 'scope-abc123'."
    },
    "name": {
      "type": "string",
      "description": "Namn på processen eller kartan."
    },
    "brief": {
      "type": "object",
      "description": "Övergripande scoping-info för hela kartan.",
      "properties": {
        "budget": {
          "type": "number",
          "description": "Budget i kr/mån."
        },
        "goal": {
          "type": "string",
          "enum": [
            "fler-kunder",
            "retention",
            "effektivisering",
            "research",
            "overvakning",
            "annat"
          ]
        },
        "techMaturity": {
          "type": "string",
          "enum": [
            "nybörjare",
            "medel",
            "avancerad"
          ]
        },
        "hardRequirements": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Hårda krav, t.ex. 'gdpr-strikt', 'self-hosted'."
        },
        "notes": {
          "type": "string",
          "description": "Fritext: scope-läge, medvetna uteslutningar, parkerade projektåtgärder som inte är noder."
        }
      }
    },
    "domain": {
      "type": "object",
      "description": "Semantisk modell — noder och relationer, oberoende av layout.",
      "required": [
        "nodes",
        "edges"
      ],
      "properties": {
        "nodes": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "id",
              "data"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "data": {
                "type": "object",
                "required": [
                  "kind",
                  "label"
                ],
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "process",
                      "form",
                      "email",
                      "ai",
                      "document",
                      "decision",
                      "meeting",
                      "system",
                      "database",
                      "role",
                      "service"
                    ],
                    "description": "Typ av nod. Välj den som bäst beskriver stegets karaktär."
                  },
                  "label": {
                    "type": "string",
                    "description": "Kort, beskrivande namn på steget (max ~40 tecken)."
                  },
                  "owner": {
                    "type": "object",
                    "description": "Ansvarig för just det här steget. Utelämnas när fasens ansvarig räcker.",
                    "required": [
                      "name"
                    ],
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "role": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      }
                    }
                  },
                  "phaseId": {
                    "type": "string",
                    "description": "ID på fasen (domain.phases[].id) som noden hör till."
                  },
                  "state": {
                    "type": "string",
                    "enum": [
                      "current",
                      "planned",
                      "sunset"
                    ],
                    "description": "Nuläge / önskat läge / utfasas — grund för de tre härledda vyerna."
                  },
                  "dueDate": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                    "description": "Klart senast, ISO yyyy-mm-dd. När den planerade ändringen ska vara genomförd. Sätts av kunden — aldrig av en mall, se beslut 12 (organisationsspecifika värden)."
                  },
                  "notes": {
                    "type": "string",
                    "description": "Fri anteckning om steget."
                  },
                  "duration": {
                    "type": "number",
                    "description": "Tidsåtgång (numeriskt)."
                  },
                  "durationUnit": {
                    "type": "string",
                    "enum": [
                      "minut",
                      "timme",
                      "dag",
                      "vecka"
                    ]
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "currentState": {
                    "type": "string",
                    "description": "Nuläge: vilket system/teknik hanterar detta idag (t.ex. 'Excel', 'SAP', 'manuellt')."
                  },
                  "gap": {
                    "type": "string",
                    "description": "Behov/gap: vad som saknas eller skaver i nuläget."
                  },
                  "solutionTypes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Lösningstyper (öppen lista): 'plugin', 'chatbot', 'automation', 'api-integration', 'dashboard', 'lead-scraping', m.fl."
                  },
                  "hitl": {
                    "type": "object",
                    "description": "Mänsklig kontrollpunkt (Human-in-the-loop).",
                    "required": [
                      "needed"
                    ],
                    "properties": {
                      "needed": {
                        "type": "boolean"
                      },
                      "phase": {
                        "type": "string",
                        "enum": [
                          "before",
                          "during",
                          "after"
                        ]
                      },
                      "description": {
                        "type": "string"
                      }
                    }
                  },
                  "fallback": {
                    "type": "string",
                    "description": "Teknisk/säkerhetsmässig reserv om automationen fallerar."
                  },
                  "gdpr": {
                    "type": "object",
                    "description": "GDPR/personuppgifter i steget. Genererar 🔒-badge på kortet.",
                    "properties": {
                      "personalData": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Kategorier, t.ex. ['namn', 'e-post', 'personnummer']."
                      },
                      "legalBasis": {
                        "type": "string",
                        "enum": [
                          "samtycke",
                          "avtal",
                          "rattslig-skyldighet",
                          "vitala-intressen",
                          "allmant-intresse",
                          "berattigat-intresse"
                        ]
                      },
                      "sensitiveData": {
                        "type": "boolean",
                        "description": "Känsliga kategorier (Art. 9)."
                      },
                      "dataController": {
                        "type": "string",
                        "description": "Vem är personuppgiftsansvarig."
                      },
                      "retentionDays": {
                        "type": "number",
                        "description": "Lagringstid i dagar."
                      },
                      "thirdPartyTransfer": {
                        "type": "boolean",
                        "description": "Skickas data till tredje part?"
                      }
                    }
                  },
                  "economy": {
                    "type": "object",
                    "description": "Ekonomi/KPI för steget. 'priority' genererar prioritets-badge; talvärdena driver kostnads-/ROI-rapporten.",
                    "properties": {
                      "monthlyCost": {
                        "type": "number",
                        "description": "kr/mån i nuläget."
                      },
                      "monthlySaving": {
                        "type": "number",
                        "description": "kr/mån förväntad besparing efter åtgärd."
                      },
                      "implementationCost": {
                        "type": "number",
                        "description": "kr engångskostnad för att genomföra åtgärden."
                      },
                      "conversionValue": {
                        "type": "number",
                        "description": "kr värde per konvertering/utfall i steget."
                      },
                      "conversionValueLabel": {
                        "type": "string",
                        "description": "Enhet, t.ex. 'SEK/lead'."
                      },
                      "costNow": {
                        "type": "string",
                        "description": "Fritext om nulägeskostnaden."
                      },
                      "estimatedSaving": {
                        "type": "string",
                        "description": "Fritext om besparingen."
                      },
                      "kpis": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Mått/KPI:er för steget."
                      },
                      "priority": {
                        "type": "string",
                        "enum": [
                          "high",
                          "medium",
                          "low"
                        ],
                        "description": "Åtgärdsprioritet."
                      }
                    }
                  },
                  "marker": {
                    "type": "object",
                    "description": "Färgmarkering på kortet.",
                    "required": [
                      "shape",
                      "color"
                    ],
                    "properties": {
                      "shape": {
                        "type": "string",
                        "enum": [
                          "circle",
                          "square",
                          "diamond"
                        ]
                      },
                      "color": {
                        "type": "string",
                        "description": "Hex-färg, t.ex. '#f97316'."
                      }
                    }
                  },
                  "actor": {
                    "type": "string",
                    "enum": [
                      "human",
                      "system",
                      "hybrid"
                    ]
                  },
                  "systemRef": {
                    "type": "string",
                    "description": "Referens till vilket system som används i steget."
                  },
                  "trigger": {
                    "type": "string",
                    "description": "Vad som startar detta steg."
                  },
                  "processTime": {
                    "type": "number",
                    "description": "Aktiv arbetstid i minuter."
                  },
                  "waitTime": {
                    "type": "number",
                    "description": "Väntetid i minuter."
                  },
                  "volume": {
                    "type": "object",
                    "required": [
                      "count",
                      "per"
                    ],
                    "properties": {
                      "count": {
                        "type": "number"
                      },
                      "per": {
                        "type": "string",
                        "enum": [
                          "dag",
                          "vecka",
                          "månad"
                        ]
                      }
                    }
                  },
                  "automationStatus": {
                    "type": "string",
                    "enum": [
                      "manual",
                      "semi",
                      "automated"
                    ]
                  },
                  "humanDecision": {
                    "type": "boolean"
                  },
                  "decisionType": {
                    "type": "string",
                    "enum": [
                      "konflikt",
                      "pris",
                      "undantag",
                      "godkännande"
                    ]
                  },
                  "failureModes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "serviceMeta": {
                    "type": "object",
                    "description": "Används när kind='service'.",
                    "properties": {
                      "vendor": {
                        "type": "string"
                      },
                      "category": {
                        "type": "string",
                        "enum": [
                          "automation",
                          "analytics",
                          "crm",
                          "email",
                          "ai",
                          "communication",
                          "storage",
                          "other"
                        ]
                      },
                      "estimatedMonthlyCost": {
                        "type": "number"
                      },
                      "costUnit": {
                        "type": "string",
                        "enum": [
                          "flat",
                          "per-seat",
                          "usage",
                          "free"
                        ]
                      },
                      "integrationComplexity": {
                        "type": "string",
                        "enum": [
                          "low",
                          "medium",
                          "high"
                        ]
                      },
                      "gdprStatus": {
                        "type": "string",
                        "enum": [
                          "compliant",
                          "partial",
                          "non-compliant"
                        ]
                      },
                      "apiAvailable": {
                        "type": "boolean"
                      },
                      "securityNotes": {
                        "type": "string"
                      },
                      "website": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "edges": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "id",
              "source",
              "target"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "source": {
                "type": "string",
                "description": "ID på källnoden."
              },
              "target": {
                "type": "string",
                "description": "ID på målnoden."
              },
              "data": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "information",
                      "material",
                      "decision"
                    ]
                  },
                  "connectionKind": {
                    "type": "string",
                    "enum": [
                      "information",
                      "handoff",
                      "integration"
                    ]
                  },
                  "handoffType": {
                    "type": "string",
                    "enum": [
                      "automated",
                      "manual"
                    ]
                  },
                  "condition": {
                    "type": "string",
                    "description": "Villkor för kanten, t.ex. 'Ja' eller 'Nej' vid beslutsnod."
                  },
                  "latency": {
                    "type": "number",
                    "description": "Fördröjning i minuter."
                  },
                  "state": {
                    "type": "string",
                    "enum": [
                      "current",
                      "planned",
                      "sunset"
                    ],
                    "description": "Befintlig / planerad / utfasad relation (t.ex. önskad koppling som inte finns idag)."
                  }
                }
              }
            }
          }
        },
        "phases": {
          "type": "array",
          "description": "Semantiska faser: grupperingar av noder (scoping-/etappenheter). Presentationen (rektangelns position/storlek/färg) ligger i layout via samma id.",
          "items": {
            "type": "object",
            "required": [
              "id",
              "label"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "label": {
                "type": "string",
                "description": "Fasens namn, t.ex. 'Bokning'."
              },
              "owner": {
                "type": "object",
                "description": "Ansvarig för processdelen — svaret på 'vem frågar jag om det här?'. Fristående från role-noder.",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "role": {
                    "type": "string",
                    "description": "Titel eller funktion, t.ex. 'Säljchef'."
                  },
                  "email": {
                    "type": "string"
                  }
                }
              },
              "stakeholders": {
                "type": "array",
                "description": "Övriga berörda, som fritext: 'Anna, ekonomi'.",
                "items": {
                  "type": "string"
                }
              },
              "order": {
                "type": "number",
                "description": "Vänster→höger-ordning (0, 1, 2…)."
              },
              "color": {
                "type": "string",
                "description": "Highlight-/fokusfärg, hex."
              },
              "state": {
                "type": "string",
                "enum": [
                  "current",
                  "planned",
                  "sunset"
                ]
              },
              "priority": {
                "type": "string",
                "enum": [
                  "high",
                  "medium",
                  "low"
                ]
              },
              "notes": {
                "type": "string"
              },
              "kpis": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "economy": {
                "type": "object",
                "description": "Summeras för åtgärdsförslag/offert per etapp.",
                "properties": {
                  "monthlyCost": {
                    "type": "number"
                  },
                  "monthlySaving": {
                    "type": "number"
                  },
                  "implementationCost": {
                    "type": "number"
                  },
                  "priority": {
                    "type": "string",
                    "enum": [
                      "high",
                      "medium",
                      "low"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "layout": {
      "type": "object",
      "description": "Visuell layout separerad från semantiken. VALFRI vid import: authoring-filer (t.ex. LLM-genererade) kan utelämna hela blocket — Mappify räknar då ut positionerna automatiskt. Kartor som sparas eller exporteras av appen innehåller alltid layout.",
      "required": [
        "nodes",
        "edges",
        "viewport"
      ],
      "properties": {
        "nodes": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "id",
              "position"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "enum": [
                  "editable",
                  "phase"
                ],
                "default": "editable",
                "description": "React Flow-renderingskomponent. Nästan alltid 'editable'. Använd 'phase' endast för fas-bakgrundsrutor. Sätt ALDRIG till nod-kinden (process, meeting, service, …) — det bryter renderingen till en tom grå ruta."
              },
              "position": {
                "type": "object",
                "required": [
                  "x",
                  "y"
                ],
                "properties": {
                  "x": {
                    "type": "number"
                  },
                  "y": {
                    "type": "number"
                  }
                }
              },
              "style": {
                "type": "object",
                "description": "Geometri för fas-rutor: width/height. Bara för type='phase'.",
                "properties": {
                  "width": {
                    "type": "number"
                  },
                  "height": {
                    "type": "number"
                  }
                }
              },
              "zIndex": {
                "type": "number"
              },
              "locked": {
                "type": "boolean",
                "description": "Noden är låst mot flytt och storleksändring. Redigeringsegenskap, inte semantik."
              }
            }
          }
        },
        "edges": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "id"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "animated": {
                "type": "boolean"
              },
              "label": {
                "type": "string"
              },
              "pathStyle": {
                "type": "string",
                "enum": [
                  "kurva",
                  "vinklad",
                  "rak"
                ],
                "description": "Bana för denna koppling. Utelämnad = layout.edgeDefaults.pathStyle."
              },
              "waypoints": {
                "type": "array",
                "description": "Brytpunkter banan sveper genom, i flödeskoordinater. Ren layout — påverkar aldrig relationens betydelse.",
                "items": {
                  "type": "object",
                  "required": [
                    "x",
                    "y"
                  ],
                  "properties": {
                    "x": {
                      "type": "number"
                    },
                    "y": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          }
        },
        "viewport": {
          "type": "object",
          "required": [
            "x",
            "y",
            "zoom"
          ],
          "properties": {
            "x": {
              "type": "number"
            },
            "y": {
              "type": "number"
            },
            "zoom": {
              "type": "number"
            }
          }
        },
        "edgeDefaults": {
          "type": "object",
          "description": "Kartans standardutseende för kopplingar. Enskilda kanter kan avvika.",
          "properties": {
            "pathStyle": {
              "type": "string",
              "enum": [
                "kurva",
                "vinklad",
                "rak"
              ],
              "description": "Bana för denna koppling. Utelämnad = layout.edgeDefaults.pathStyle."
            }
          }
        }
      }
    }
  }
}
