{
  "profile": {
    "name": "Shawn Evans",
    "role": "Software Engineer",
    "summary": "I build practical software systems: tools that keep their data straight, take repetitive work off people, and are tested the way people actually use them.",
    "detail": "Recent work ranges from a full-featured Discord application for tabletop communities to a multi-step loan application tested for accessibility and across browsers.",
    "builds": ["Discord applications", "Multi-step web applications", "Automation and data tooling"],
    "emphasis": ["Systems thinking", "Reliability", "Automation", "Testing", "Accessibility"],
    "website": "https://shawnevans.dev"
  },
  "availability": {
    "open_to_roles": true,
    "role_types": ["Software engineering", "Automation", "Product tooling", "Technical problem-solving"]
  },
  "contact": {
    "email": "work@shawnevans.dev",
    "github": "https://github.com/Sevens-Dev",
    "linkedin": "https://www.linkedin.com/in/shawnevanscsit/"
  },
  "projects": [
    {
      "id": "dattebotyo",
      "priority": 1,
      "name": "DatteBotYo",
      "type": "Discord application for Naruto 5e communities",
      "summary": "A full-featured Discord application that runs Naruto 5e play inside the server where it happens: character data, dice and combat, initiative, missions, resources, and rules reference in one bot.",
      "context": "A campaign run over Discord keeps its state in several places at once: character spreadsheets, chat history, and whoever is tracking the fight. Rolls, turn order, and rules questions all depend on finding the right number somewhere else.",
      "system": {
        "inputs": ["Discord commands from players and GMs", "Google Sheets character sheets"],
        "modules": ["Sheet import", "Dice engine", "Attacks, saves, and checks", "Initiative tracking", "Missions", "Resource tracking", "Jutsu and feat lookup"],
        "persistence": ["MySQL: characters, stats, and resources", "Jutsu and feat database"],
        "output": "Results posted back to the channel"
      },
      "decisions": [
        {
          "title": "Import instead of re-entry",
          "detail": "Characters are imported from Google Sheets (stats, saves, skills, attack bonuses, chakra, and HP) and stored in MySQL, so players can switch characters and carry data across sessions."
        },
        {
          "title": "Guard shared state",
          "detail": "Resource commands for Ryo and downtime validate every change, so a balance can never drop below zero."
        },
        {
          "title": "A dice engine, not a random number",
          "detail": "Supports exploding dice, conditional rerolls, minimum values, arithmetic expressions such as (2d6+1d4)*2, advantage and disadvantage, and repeated rolls with summaries."
        },
        {
          "title": "Tolerate imperfect input",
          "detail": "Slightly mistyped stat or skill names resolve to the closest match. Jutsu and feat searches accept partial names and ask the user to choose when a result is ambiguous."
        },
        {
          "title": "Keep the session in one place",
          "detail": "Attack rolls use bonuses from the imported sheet, and initiative tracking and mission tools keep the flow of play inside Discord."
        }
      ],
      "stack": ["Python", "discord.py", "MySQL", "Google Sheets API"],
      "links": {
        "repository": "https://github.com/Sevens-Dev/DatteBotYo"
      }
    },
    {
      "id": "lendswift",
      "priority": 2,
      "name": "LendSwift loan application",
      "type": "Multi-step web application",
      "confidential": true,
      "disclosure": "Confidential work. Described at a high level only; code, screens, and implementation details are intentionally not shown.",
      "summary": "A multi-step React loan application built on schema-backed validation and document workflows, with complete applicant journeys tested for accessibility and across browsers.",
      "context": "Multi-step applications fail in the gaps: between steps, between browsers, and for people who don't use a mouse. Correctness has to be checked across the whole journey, not one field at a time.",
      "decisions": [
        {
          "title": "Validation as a schema",
          "detail": "Form rules are declared as schemas with Zod and enforced through React Hook Form."
        },
        {
          "title": "Documents inside the journey",
          "detail": "Document workflows are part of the applicant journey and are tested with it."
        },
        {
          "title": "Test complete journeys",
          "detail": "Cypress and Playwright exercise complete applicant journeys end to end, across browsers."
        },
        {
          "title": "Accessibility as coverage",
          "detail": "Accessibility is part of the test coverage, alongside functional behavior."
        }
      ],
      "stack": ["React", "React Hook Form", "Zod", "Cypress", "Playwright"],
      "links": {}
    }
  ],
  "other_work": [
    {
      "name": "Daymark",
      "summary": "Local-first daily planning dashboard for priorities, habits, reflection, and weekly patterns.",
      "stack": ["React", "Local-first storage"]
    },
    {
      "name": "Crumbling Whispers",
      "summary": "Foundry VTT v12 module for private player prompts, built around message privacy and version compatibility.",
      "stack": ["JavaScript", "Foundry VTT"]
    },
    {
      "name": "Egoist combat tracker",
      "summary": "Standalone browser tool and formula-driven reference workbook for a dense tabletop combat system.",
      "stack": ["HTML", "CSS", "JavaScript", "Excel", "Playwright"]
    },
    {
      "name": "Palworld metadata pipeline",
      "summary": "Extracts and normalizes game metadata into readable passive-skill catalogs and optimizer-ready data.",
      "stack": ["Python"]
    }
  ],
  "principles": [
    {
      "title": "Make state explicit",
      "detail": "Decide where data lives, how it gets in, and what is allowed to change it before building the interface on top.",
      "seen_in": ["DatteBotYo", "LendSwift"]
    },
    {
      "title": "Automate the repetitive path",
      "detail": "If people copy numbers between places or do the arithmetic by hand, that is work the software should be doing.",
      "seen_in": ["DatteBotYo"]
    },
    {
      "title": "Design for imperfect input",
      "detail": "People mistype, abbreviate, and guess. Close matching and clear prompts beat a failed command.",
      "seen_in": ["DatteBotYo"]
    },
    {
      "title": "Test complete journeys",
      "detail": "Multi-step software breaks between the steps. End-to-end tests should follow the path a real user takes, in more than one browser.",
      "seen_in": ["LendSwift"]
    },
    {
      "title": "Treat accessibility as correctness",
      "detail": "Keyboard access, labels, and clear feedback are part of whether software works, so they belong in test coverage.",
      "seen_in": ["LendSwift", "shawnevans.dev"]
    }
  ],
  "toolkit": {
    "languages": ["Python", "JavaScript", "SQL", "HTML", "CSS"],
    "application": ["discord.py", "React", "React Hook Form", "Zod"],
    "data_and_integration": ["MySQL", "Google Sheets API"],
    "testing": ["Cypress", "Playwright"]
  }
}
