commit aa6300fa235154cb5bfd15bec75ad082a8905b74 Author: Dylan Garvis Date: Mon Aug 10 17:49:02 2026 -0400 docs(design): define Leaf user stories diff --git a/design/index.md b/design/index.md new file mode 100644 index 0000000..e63bb22 --- /dev/null +++ b/design/index.md @@ -0,0 +1,12 @@ +--- +okf_version: "0.1" +--- + +# Leaf Design + +This bundle documents Leaf, a Spigot plugin that lets players opt into a visible Resistance boost while requiring them to relinquish that protection when they attack another player. + +## Explore + +- [User stories](user-stories/index.md) +- [Design log](log.md) diff --git a/design/log.md b/design/log.md new file mode 100644 index 0000000..56f1443 --- /dev/null +++ b/design/log.md @@ -0,0 +1,16 @@ +# Leaf Design Log + +## 2026-08-10 + +### Initial protection design + +- Leaf is available to any player who opts in; the seven-day period applies only to onboarding reminders. +- Protection grants Resistance I by default and remains active until the player opts out, attacks another player, an administrator disables it for the player, or Leaf is globally disabled. +- Receiving an attack does not remove protection, but retaliating does, including attributable Thorns damage. +- PvP attribution covers melee, projectiles, potions, owned animals, Thorns, and indirect damage when Spigot exposes a reliable responsible player. +- Opted-in players receive a leaf prefix in tab, overhead names, and chat where supported. +- New players receive an onboarding reminder on every login for seven calendar days after first joining. +- Global disablement suppresses effects, prefixes, and reminders without erasing player choices. +- Administration uses the permission-aware `/leaf` command tree with autocomplete. +- Builds and releases follow the neighboring Spigot Base Gradle and Gitea pipeline. +- The design bundle is committed together; later implementation work is committed separately for each user story. diff --git a/design/user-stories/index.md b/design/user-stories/index.md new file mode 100644 index 0000000..d007697 --- /dev/null +++ b/design/user-stories/index.md @@ -0,0 +1,9 @@ +# Leaf User Stories + +1. [US-001: Opt into Leaf protection](us-001-opt-into-leaf-protection.md) +2. [US-002: Relinquish protection when attacking](us-002-relinquish-protection-when-attacking.md) +3. [US-003: Identify protected players](us-003-identify-protected-players.md) +4. [US-004: Introduce new players to Leaf](us-004-introduce-new-players-to-leaf.md) +5. [US-005: Administer Leaf](us-005-administer-leaf.md) +6. [US-006: Configure and persist Leaf](us-006-configure-and-persist-leaf.md) +7. [US-007: Build and release Leaf](us-007-build-and-release-leaf.md) diff --git a/design/user-stories/us-001-opt-into-leaf-protection.md b/design/user-stories/us-001-opt-into-leaf-protection.md new file mode 100644 index 0000000..74c9857 --- /dev/null +++ b/design/user-stories/us-001-opt-into-leaf-protection.md @@ -0,0 +1,28 @@ +--- +type: User Story +title: "US-001: Opt into Leaf protection" +description: Let players voluntarily receive and relinquish a persistent Resistance boost. +status: backlog +--- + +# US-001: Opt into Leaf protection + +As a **player**, I want to opt into Leaf protection so that I can receive a modest defensive boost while playing on a hard server. + +## Acceptance criteria + +- [ ] Players with the `leaf.use` permission, granted by default, can use `/leaf on`, `/leaf off`, and `/leaf status`. +- [ ] `/leaf on` records the player's opt-in choice and grants Resistance I while Leaf is globally enabled. +- [ ] Resistance remains continuously effective without distracting expiry or renewal messages or particles. +- [ ] `/leaf off` records the player's opt-out choice and immediately removes only the Resistance effect managed by Leaf. +- [ ] `/leaf status` clearly distinguishes the player's saved choice, active protection, administrative lock, and global Leaf state. +- [ ] Repeating an already-satisfied `on` or `off` command is safe and explains that no change was needed. +- [ ] Opt-in choices are keyed by UUID and survive logout and server restart. +- [ ] A player who joins while opted in regains protection when Leaf is enabled. +- [ ] Player-command autocomplete suggests only valid next arguments available to the sender. + +## Related + +- [US-002: Relinquish protection when attacking](us-002-relinquish-protection-when-attacking.md) +- [US-003: Identify protected players](us-003-identify-protected-players.md) +- [US-005: Administer Leaf](us-005-administer-leaf.md) diff --git a/design/user-stories/us-002-relinquish-protection-when-attacking.md b/design/user-stories/us-002-relinquish-protection-when-attacking.md new file mode 100644 index 0000000..d9f08fd --- /dev/null +++ b/design/user-stories/us-002-relinquish-protection-when-attacking.md @@ -0,0 +1,30 @@ +--- +type: User Story +title: "US-002: Relinquish protection when attacking" +description: Remove Leaf protection when an opted-in player attacks another player. +status: backlog +--- + +# US-002: Relinquish protection when attacking + +As a **player facing PvP**, I want Leaf protection to belong only to non-aggressors so that protected players cannot keep its advantage after fighting back. + +## Acceptance criteria + +- [ ] When an opted-in player damages another player, Leaf automatically changes the attacker's saved choice to opted out. +- [ ] Automatic opt-out immediately removes Leaf-managed Resistance and the attacker's leaf prefix. +- [ ] The attacker receives a clear chat message explaining that attacking another player disabled Leaf and that they may opt in again when permitted. +- [ ] Receiving player-caused damage without retaliating does not change the protected player's choice or Resistance. +- [ ] Retaliatory damage counts as attacking, including Thorns damage attributable to the protected player. +- [ ] Direct melee attacks and player-fired projectiles are attributed to the attacking player. +- [ ] Harmful splash or lingering potion damage is attributed to the player who threw the potion. +- [ ] Damage caused by a tamed animal is attributed to its player owner when Spigot exposes that ownership. +- [ ] TNT, fire, and other indirect damage trigger opt-out only when Spigot exposes a reliable responsible player; ambiguous environmental damage does not opt out an innocent player. +- [ ] PvP-triggered opt-out applies even when an administrator has locked the player's preference. +- [ ] A single attack produces no duplicate state changes or duplicate notifications. + +## Related + +- [US-001: Opt into Leaf protection](us-001-opt-into-leaf-protection.md) +- [US-003: Identify protected players](us-003-identify-protected-players.md) +- [US-005: Administer Leaf](us-005-administer-leaf.md) diff --git a/design/user-stories/us-003-identify-protected-players.md b/design/user-stories/us-003-identify-protected-players.md new file mode 100644 index 0000000..5a83b8b --- /dev/null +++ b/design/user-stories/us-003-identify-protected-players.md @@ -0,0 +1,27 @@ +--- +type: User Story +title: "US-003: Identify protected players" +description: Mark actively protected players with a visible leaf prefix wherever Spigot supports it. +status: backlog +--- + +# US-003: Identify protected players + +As a **server participant**, I want protected players to be visibly identified so that their Leaf status is clear before I interact with them. + +## Acceptance criteria + +- [ ] An actively protected player has a configurable leaf prefix before their name in the player list. +- [ ] An actively protected player has the same prefix before their overhead name where Spigot supports it. +- [ ] An actively protected player has the same prefix in standard Spigot chat where the active chat format supports it. +- [ ] The default prefix uses a leaf symbol with readable spacing and Minecraft-compatible formatting. +- [ ] The prefix is removed immediately when the player opts out or is opted out by PvP or an administrator. +- [ ] Prefixes are suppressed while Leaf is globally disabled and restored for online opted-in players when it is re-enabled. +- [ ] Prefix updates do not overwrite unrelated display-name text where the Spigot API allows the values to coexist. +- [ ] Scoreboard-team and third-party chat-plugin compatibility limitations are documented, and unsupported integrations fail without affecting protection state. + +## Related + +- [US-001: Opt into Leaf protection](us-001-opt-into-leaf-protection.md) +- [US-002: Relinquish protection when attacking](us-002-relinquish-protection-when-attacking.md) +- [US-006: Configure and persist Leaf](us-006-configure-and-persist-leaf.md) diff --git a/design/user-stories/us-004-introduce-new-players-to-leaf.md b/design/user-stories/us-004-introduce-new-players-to-leaf.md new file mode 100644 index 0000000..30c7f0c --- /dev/null +++ b/design/user-stories/us-004-introduce-new-players-to-leaf.md @@ -0,0 +1,27 @@ +--- +type: User Story +title: "US-004: Introduce new players to Leaf" +description: Remind players how to control Leaf during their first seven calendar days on the server. +status: backlog +--- + +# US-004: Introduce new players to Leaf + +As a **new player**, I want a brief explanation of Leaf when I join so that I know protection is available and understand how to control it. + +## Acceptance criteria + +- [ ] Leaf records the first observed join time for each player by UUID as an RFC 3339 UTC timestamp. +- [ ] On every login before the first-join timestamp plus seven calendar days, the player receives a concise welcome message explaining Leaf protection. +- [ ] The welcome message tells the player to use `/leaf on`, `/leaf off`, and `/leaf status`. +- [ ] The message makes clear that attacking another player automatically opts the attacker out. +- [ ] Players no longer receive the welcome message once their seven-day onboarding period expires. +- [ ] Existing first-join timestamps are not reset by logout, restart, opt-in changes, or global disablement. +- [ ] No onboarding reminders are shown while Leaf is globally disabled. +- [ ] Re-enabling Leaf allows reminders to resume on subsequent logins only for players whose original seven-day period has not expired. + +## Related + +- [US-001: Opt into Leaf protection](us-001-opt-into-leaf-protection.md) +- [US-005: Administer Leaf](us-005-administer-leaf.md) +- [US-006: Configure and persist Leaf](us-006-configure-and-persist-leaf.md) diff --git a/design/user-stories/us-005-administer-leaf.md b/design/user-stories/us-005-administer-leaf.md new file mode 100644 index 0000000..9547352 --- /dev/null +++ b/design/user-stories/us-005-administer-leaf.md @@ -0,0 +1,32 @@ +--- +type: User Story +title: "US-005: Administer Leaf" +description: Give administrators command-based control over global and per-player Leaf behavior. +status: backlog +--- + +# US-005: Administer Leaf + +As a **server administrator**, I want to control Leaf globally and per player so that I can support players, prevent misuse, and suspend protection for server events. + +## Acceptance criteria + +- [ ] Administrative commands require `leaf.admin`, which server operators receive by default. +- [ ] `/leaf enabled ` globally enables or disables Leaf. +- [ ] Global disablement immediately suppresses Leaf-managed Resistance, prefixes, and onboarding reminders without erasing player opt-in choices. +- [ ] Global enablement immediately restores protection and prefixes for eligible online opted-in players. +- [ ] `/leaf player status` reports the player's identity, saved opt-in choice, active-protection state, lock state, and first-join time. +- [ ] `/leaf player enabled ` changes the player's saved opt-in choice and immediately reconciles their online effect and prefix. +- [ ] `/leaf player locked ` controls whether that player can change their own saved choice. +- [ ] A locked player receives a clear explanation when `/leaf on` or `/leaf off` is denied. +- [ ] PvP-triggered opt-out remains authoritative even for a locked player. +- [ ] Player targets resolve online names, previously known names, and UUIDs without confusing two players who used the same name. +- [ ] `/leaf strength <1-5>` changes the live Resistance level and immediately updates protected online players. +- [ ] Administrative autocomplete is permission-aware and suggests valid subcommands, known player targets, properties, levels, and `on` or `off` values for the current argument position. +- [ ] Every successful mutation reports exactly what changed, and invalid requests make no partial changes. + +## Related + +- [US-001: Opt into Leaf protection](us-001-opt-into-leaf-protection.md) +- [US-002: Relinquish protection when attacking](us-002-relinquish-protection-when-attacking.md) +- [US-006: Configure and persist Leaf](us-006-configure-and-persist-leaf.md) diff --git a/design/user-stories/us-006-configure-and-persist-leaf.md b/design/user-stories/us-006-configure-and-persist-leaf.md new file mode 100644 index 0000000..9c48bb7 --- /dev/null +++ b/design/user-stories/us-006-configure-and-persist-leaf.md @@ -0,0 +1,30 @@ +--- +type: User Story +title: "US-006: Configure and persist Leaf" +description: Provide validated configuration and durable, defensive storage for Leaf behavior. +status: backlog +--- + +# US-006: Configure and persist Leaf + +As a **server operator**, I want Leaf settings and player state to be validated and durable so that protection remains predictable across restarts. + +## Acceptance criteria + +- [ ] Configuration supports the global enabled state, Resistance strength, leaf prefix, onboarding duration, and player-facing messages. +- [ ] Resistance strength defaults to level I and accepts only Minecraft Resistance levels I through V. +- [ ] Runtime changes made through `/leaf enabled` and `/leaf strength` are persisted for subsequent restarts. +- [ ] UUID-keyed player state persists the latest known name, saved opt-in choice, administrative lock, and first-join timestamp. +- [ ] Date-times use RFC 3339 UTC notation with a `Z` suffix. +- [ ] State is saved safely so that a failed write does not replace valid persisted state with a partial document. +- [ ] Invalid required configuration prevents partial plugin initialization and produces a clear server log message. +- [ ] Corrupt or invalid player records are handled defensively and cannot silently grant protection or privileges. +- [ ] Removing Leaf-managed Resistance does not remove a distinct Resistance effect that Leaf does not own when the API provides enough information to distinguish it. +- [ ] Unknown forward-compatible configuration and player-state fields are preserved where practical. + +## Related + +- [US-001: Opt into Leaf protection](us-001-opt-into-leaf-protection.md) +- [US-004: Introduce new players to Leaf](us-004-introduce-new-players-to-leaf.md) +- [US-005: Administer Leaf](us-005-administer-leaf.md) +- [US-007: Build and release Leaf](us-007-build-and-release-leaf.md) diff --git a/design/user-stories/us-007-build-and-release-leaf.md b/design/user-stories/us-007-build-and-release-leaf.md new file mode 100644 index 0000000..9f48053 --- /dev/null +++ b/design/user-stories/us-007-build-and-release-leaf.md @@ -0,0 +1,30 @@ +--- +type: User Story +title: "US-007: Build and release Leaf" +description: Give maintainers repeatable Spigot builds, automated verification, and versioned Gitea releases. +status: backlog +--- + +# US-007: Build and release Leaf + +As a **plugin maintainer**, I want automated builds and releases modeled on Spigot Base so that tested, correctly versioned Leaf artifacts can be distributed consistently. + +## Acceptance criteria + +- [ ] The Gradle project compiles against Spigot API `26.2-R0.1-SNAPSHOT` using a Java 17 toolchain. +- [ ] Compiler lint warnings fail the build. +- [ ] Automated JUnit 5 tests run as part of the Gradle check lifecycle. +- [ ] Pushes and pull requests build and test Leaf in Gitea Actions. +- [ ] Pull requests validate conventional commit messages. +- [ ] CI stores a development Leaf JAR as a workflow artifact. +- [ ] Main-branch conventional commits drive semantic versioning. +- [ ] A successful release builds a versioned Leaf JAR and attaches it to the corresponding Gitea release. +- [ ] Build files, Gradle wrapper, workflows, and release behavior follow `../spigot-base/` where applicable while using Leaf names and identifiers. +- [ ] The initial approved user-story bundle is kept in one documentation commit. +- [ ] Subsequent implementation work is organized into a separate conventional commit for each implemented user story. +- [ ] No remote push is performed until the maintainer confirms that the Gitea repository and release token secret are ready. + +## Related + +- [US-006: Configure and persist Leaf](us-006-configure-and-persist-leaf.md) +- [User-story catalog](index.md)