diff --git a/CC.md b/CC.md new file mode 100644 index 00000000..54966720 --- /dev/null +++ b/CC.md @@ -0,0 +1,207 @@ +NIP-CC +====== + +Geocaching Events +----------------- + +`draft` `optional` + +This NIP defines event kinds for geocaching activities on Nostr, enabling users to create, discover, and log geocaches in a decentralized manner. + +## Motivation + +Geocaching is a global treasure hunting game where participants use GPS coordinates to hide and seek containers ("geocaches") at specific locations. This NIP brings geocaching to Nostr, allowing for censorship-resistant, decentralized geocache listings and logs without relying on centralized platforms. + +## Event Kinds + +This NIP defines two new event kinds: + +- `kind:37515`: Geocache listing (addressable event) +- `kind:37516`: Geocache log entry + +## Geocache Listing (kind:37515) + +A geocache listing is an addressable event that describes a hidden geocache. The event is addressable to allow cache owners to update their listings (e.g., to provide maintenance updates or adjust coordinates). + +### Content + +The `.content` field contains the cache description as plain text. + +### Tags + +Required tags: +- `d` (required): Unique identifier for the geocache +- `name` (required): The name of the geocache +- `g` (required): Geohash of the cache location (minimum 6 characters precision) +- `location` (required): Human-readable location description (e.g., "Central Park, New York") +- `difficulty` (required): Integer from 1-5 indicating puzzle/finding difficulty (1=easiest, 5=hardest) +- `terrain` (required): Integer from 1-5 indicating physical difficulty (1=wheelchair accessible, 5=specialized equipment required) +- `size` (required): One of: `micro`, `small`, `regular`, `large` +- `cache-type` (required): One of: `traditional`, `multi`, `mystery`, `earth`, `virtual`, `letterbox`, `event` + +Optional tags: +- `hint` (optional): An encrypted hint that can help seekers find the cache. Should be ROT13 encoded by convention +- `image` (optional, repeated): Image URLs related to the cache location or container +- `t` (optional, repeated): Hashtags/categories (e.g., "urban", "forest", "historical") +- `published_at` (optional): Unix timestamp when the cache was first hidden +- `status` (optional): Current cache status - `active` (default), `disabled`, or `archived` +- `relay` (optional but recommended, repeated): Preferred relays for log submissions in order of preference + +### Example + +```json +{ + "kind": 37515, + "pubkey": "", + "created_at": 1234567890, + "content": "A scenic cache along the river trail. Please be mindful of muggles during busy hours.", + "tags": [ + ["d", "riverside-mystery-2024"], + ["name", "Riverside Mystery"], + ["g", "dp3wfg"], + ["location", "Riverside Park, Portland, OR"], + ["difficulty", "2"], + ["terrain", "3"], + ["size", "small"], + ["cache-type", "traditional"], + ["hint", "Ybbx sbe gur byq bnx gerr"], + ["image", "https://example.com/cache-area.jpg"], + ["t", "scenic"], + ["t", "river"], + ["published_at", "1704067200"], + ["status", "active"], + ["relay", "wss://geocaching.example.com"], + ["relay", "wss://oregon.nostr.com"] + ] +} +``` + +## Geocache Log (kind:37516) + +A geocache log represents a user's visit to a geocache. These are regular (non-addressable) events. + +### Content + +The `.content` field contains the log message as plain text. + +### Tags + +Required tags: +- `a` (required): Reference to the geocache being logged using NIP-01 `a` tag format: `["a", "37515::", ""]`. The relay URL SHOULD be the preferred relay from the cache listing if available +- `log-type` (required): One of: + - `found`: Successfully found the cache + - `dnf`: Did Not Find despite searching + - `note`: General comment without searching + - `maintenance`: Maintenance performed by cache owner + - `disabled`: Cache temporarily disabled by owner + - `enabled`: Cache re-enabled by owner + - `archived`: Cache permanently retired + +Optional tags: +- `image` (optional, repeated): Image URLs from the visit +- `g` (optional): Geohash of where the log was created (for privacy, should be less precise than cache location) +- `published_at` (optional): Unix timestamp of the actual visit (may differ from event creation time) + +### Example + +```json +{ + "kind": 37516, + "pubkey": "", + "created_at": 1234567890, + "content": "Beautiful location! Took me 20 minutes to find it. TFTC!", + "tags": [ + ["a", "37515:abc123...:riverside-mystery-2024", "wss://geocaching.example.com"], + ["log-type", "found"], + ["image", "https://example.com/selfie.jpg"], + ["g", "dp3w"], + ["published_at", "1704153600"] + ] +} +``` + +## Relay Selection + +### For Cache Listings +Cache owners SHOULD include one or more `relay` tags in their listing events to indicate preferred relays for log submissions. Relays are listed in order of preference, with the first relay being the primary choice. + +### For Log Events +When creating log events (kind:37516), clients SHOULD: +1. Check the cache listing for `relay` tags and publish logs to those relays +2. Include the first (primary) relay URL in the `a` tag reference (third parameter) +3. Also publish to the user's regular write relays for their own activity tracking + +### Geographic and Specialized Relays +Communities MAY establish geographic or geocaching-specific relays. Clients SHOULD: +- Allow users to configure geocaching-specific relays in settings +- Consider implementing relay selection based on geohash prefixes for geographic relevance +- Support community-maintained relay lists for geocaching activities + +### Relay Discovery +When querying for geocaches and logs, clients SHOULD: +1. Use the relay hints from `a` tags when fetching referenced cache listings +2. Query both general-purpose and specialized geocaching relays +3. Consider geographic proximity when selecting relays to query + +## Client Implementation Notes + +### Querying Geocaches + +Clients SHOULD use the following filters to query geocaches: + +1. **All active geocaches**: `{"kinds": [37515], "#status": ["active"]}` +2. **Geocaches by location**: `{"kinds": [37515], "#g": ["dp3w"]}` (using geohash prefix) +3. **Geocaches by type**: `{"kinds": [37515], "#cache-type": ["mystery"]}` +4. **Geocaches by tag**: `{"kinds": [37515], "#t": ["scenic"]}` +5. **User's hidden caches**: `{"kinds": [37515], "authors": [""]}` + +### Querying Logs + +1. **Logs for a specific cache**: `{"kinds": [37516], "#a": ["37515::"]}` +2. **User's found caches**: `{"kinds": [37516], "authors": [""], "#log-type": ["found"]}` +3. **Recent activity**: `{"kinds": [37516], "limit": 50}` with time-based sorting + +### Privacy Considerations + +- Log events MAY include less precise geohashes than the cache location to protect finder privacy +- Clients SHOULD warn users before publishing precise location data +- Images SHOULD have EXIF location data stripped before uploading + +### Coordinate Handling + +- Coordinates SHOULD be stored as geohashes for efficient geographic queries +- Clients MUST support at least 6-character geohash precision (±0.61km) +- For display, clients SHOULD convert between geohash and decimal degrees + +### Statistics + +Clients MAY calculate statistics by counting log events: +- **Find count**: Count of logs with `log-type: "found"` for a cache +- **DNF rate**: Ratio of "dnf" to total "found" + "dnf" logs +- **User stats**: Count of unique caches found by a user + +## Appendix: Geocaching Terminology + +- **TFTC**: Thanks For The Cache +- **Muggle**: Non-geocacher who might accidentally discover a cache +- **DNF**: Did Not Find +- **FTF**: First To Find +- **Cache**: Short for geocache +- **CO**: Cache Owner +- **Geohash**: A geographic encoding system that represents coordinates as a short alphanumeric string + +## Security and Spam Considerations + +- Clients SHOULD implement rate limiting for cache creation +- Cache owners SHOULD be able to delete/archive their own caches +- Clients MAY implement reputation systems based on found/hidden ratios +- Clients SHOULD verify that log coordinates are reasonably close to cache coordinates + +## Future Considerations + +This NIP intentionally keeps the initial implementation simple. Future NIPs may define: +- Trackable items that move between caches +- Event caches with specific date/time meetups +- Challenge caches with specific finding requirements +- Puzzle solutions stored as encrypted content +- Integration with Lightning for premium caches or tips diff --git a/README.md b/README.md index e0b77471..1dcc714e 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos - [NIP-B7: Blossom](B7.md) - [NIP-BE: Nostr BLE Communications Protocol](BE.md) - [NIP-C0: Code Snippets](C0.md) +- [NIP-CC: Geocaching](CC.md) - [NIP-C7: Chats](C7.md) - [NIP-EE: E2EE Messaging using MLS Protocol](EE.md) --- **unrecommended**: superseded by the [Marmot Protocol](https://github.com/marmot-protocol/marmot) @@ -188,8 +189,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos | `7374` | Reserved Cashu Wallet Tokens | [60](60.md) | | `7375` | Cashu Wallet Tokens | [60](60.md) | | `7376` | Cashu Wallet History | [60](60.md) | -| `7516` | Geocache log | [geocaching][geocaching] | -| `7517` | Geocache proof of find | [geocaching][geocaching] | +| `7516` | Geocache log | [CC](CC.md) | +| `7517` | Geocache proof of find | [CC](CC.md) | | `8000` | Add User | [43](43.md) | | `8001` | Remove User | [43](43.md) | | `9000`-`9030` | Group Control Events | [29](29.md) |