kinsaga 0.2.0

A family chronicle library and CLI for managing timestamped, categorized life events
Documentation
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://git.sr.ht/~danprobst/kinsaga/schema.json",
  "title": "Kinsaga Chronicle",
  "description": "A family chronicle containing categorized life events for multiple persons",
  "type": "object",
  "required": ["version", "categories", "persons"],
  "properties": {
    "version": {
      "type": "string",
      "description": "Schema version",
      "const": "1.0"
    },
    "title": {
      "type": "string",
      "description": "Optional title for the chronicle"
    },
    "last_updated": {
      "type": "string",
      "format": "date-time",
      "description": "ISO 8601 timestamp of last modification (auto-set on save)"
    },
    "categories": {
      "type": "array",
      "description": "User-defined event categories",
      "items": {
        "$ref": "#/definitions/Category"
      }
    },
    "persons": {
      "type": "array",
      "description": "People in the chronicle",
      "items": {
        "$ref": "#/definitions/Person"
      }
    }
  },
  "definitions": {
    "Category": {
      "type": "object",
      "description": "A category for classifying facts/events",
      "required": ["id", "label"],
      "properties": {
        "id": {
          "type": "string",
          "description": "Unique identifier for the category (used in facts)",
          "pattern": "^[a-z][a-z0-9_-]*$",
          "examples": ["education", "family", "travel", "work"]
        },
        "label": {
          "type": "string",
          "description": "Human-readable display name",
          "minLength": 1,
          "examples": ["Education & Job", "Family", "Travel"]
        },
        "color": {
          "type": "string",
          "description": "Optional hex color for UI display",
          "pattern": "^#[0-9A-Fa-f]{6}$",
          "examples": ["#4A90D9", "#D94A4A"]
        }
      }
    },
    "Person": {
      "type": "object",
      "description": "A person in the chronicle",
      "required": ["id", "name", "facts"],
      "properties": {
        "id": {
          "type": "string",
          "description": "Unique identifier for the person",
          "pattern": "^[a-z][a-z0-9_-]*$",
          "examples": ["alice", "bob", "john-doe"]
        },
        "name": {
          "type": "string",
          "description": "Full display name",
          "minLength": 1,
          "examples": ["Alice Smith", "Bob Johnson"]
        },
        "facts": {
          "type": "array",
          "description": "Life events for this person",
          "items": {
            "$ref": "#/definitions/Fact"
          }
        }
      }
    },
    "Fact": {
      "type": "object",
      "description": "A life event or fact about a person",
      "required": ["id", "date", "category", "text"],
      "properties": {
        "id": {
          "type": "string",
          "description": "Unique identifier (UUID v4)",
          "format": "uuid",
          "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$",
          "examples": ["550e8400-e29b-41d4-a716-446655440000"]
        },
        "date": {
          "type": "string",
          "description": "Date in ISO 8601 format with optional ? suffix for uncertainty",
          "pattern": "^\\d{4}(-\\d{2}(-\\d{2})?)?\\??$",
          "examples": ["1987", "1987-03", "1987-03-15", "1987?", "1987-03?"]
        },
        "category": {
          "type": "string",
          "description": "Reference to a category id",
          "pattern": "^[a-z][a-z0-9_-]*$"
        },
        "text": {
          "type": "string",
          "description": "Description of the event",
          "minLength": 1
        },
        "with": {
          "type": "array",
          "description": "Other person ids involved in this event",
          "items": {
            "type": "string",
            "pattern": "^[a-z][a-z0-9_-]*$"
          }
        },
        "location": {
          "$ref": "#/definitions/Location"
        },
        "attachments": {
          "type": "array",
          "description": "Related files or media",
          "items": {
            "$ref": "#/definitions/Attachment"
          },
          "default": []
        }
      }
    },
    "Location": {
      "type": "object",
      "description": "Geographic location of an event",
      "required": ["country"],
      "properties": {
        "country": {
          "type": "string",
          "description": "Country name or ISO code",
          "minLength": 1,
          "examples": ["France", "USA", "DE"]
        },
        "place": {
          "type": "string",
          "description": "Place name (city, address, landmark, venue, etc.)",
          "examples": ["Paris", "Rifugio Auronzo", "123 Main Street, Springfield", "Eiffel Tower"]
        },
        "coordinates": {
          "$ref": "#/definitions/Coordinates"
        }
      }
    },
    "Coordinates": {
      "type": "object",
      "description": "GPS coordinates",
      "required": ["lat", "lon"],
      "properties": {
        "lat": {
          "type": "number",
          "description": "Latitude in decimal degrees",
          "minimum": -90,
          "maximum": 90,
          "examples": [48.8566, -33.8688]
        },
        "lon": {
          "type": "number",
          "description": "Longitude in decimal degrees",
          "minimum": -180,
          "maximum": 180,
          "examples": [2.3522, 151.2093]
        }
      }
    },
    "Attachment": {
      "type": "object",
      "description": "A file or media attachment",
      "required": ["url"],
      "properties": {
        "url": {
          "type": "string",
          "format": "uri",
          "description": "URL with scheme (file://, https://, s3://, etc.)",
          "examples": [
            "file:///photos/event.jpg",
            "https://example.com/doc.pdf",
            "s3://bucket/path/image.png"
          ]
        },
        "content_type": {
          "type": "string",
          "description": "MIME type",
          "pattern": "^[a-zA-Z0-9.+-]+/[a-zA-Z0-9.+-]+$",
          "examples": ["image/jpeg", "application/pdf", "video/mp4"]
        },
        "title": {
          "type": "string",
          "description": "Human-readable description",
          "examples": ["Wedding photo", "Birth certificate"]
        }
      }
    }
  }
}