Tours (kind 30823) were the only major addressable entity with no edit path: an
organizer had to delete and recreate (losing the URL/identifier) just to fix a
typo or price. Rather than duplicate the enormous multi-category tour form (and
risk schema drift / the exact tag-clobber bugs fixed earlier this session), I
made the existing CreateTourPage do double duty:
- CreateTourPage now accepts an optional `existing?: SkateTour`. When present it
prefills every field (all four categories: local/national/international/
destruction — including challenges, prize distribution, film-release, partner
shop, cities/countries, coords, dates), reuses the same `d` identifier, and
adapts copy (title, submit button, toast).
- On save it PRESERVES unmanaged tags (sponsors, tags from other clients) and
keeps any existing paid `featured` window — same "preserve unmanaged tags"
discipline as the event/shop edit fixes, since 30823 is addressable and
re-publishing replaces the whole tag set.
- Guarded the category→duration reset effect so it no longer clobbers the
prefilled duration on the first render in edit mode.
- The paid FeaturedUpgrade upsell is hidden when editing (existing status is
carried through automatically).
New EditTourPage wrapper loads the tour, gates to the owner (login / access-
denied states), and renders <CreateTourPage existing={tour} />. Added the
/edit-tour/:pubkey/:identifier route and an owner-only Edit button on
TourDetailPage beside the existing Delete control.
This closes the one concrete gap the addressable-events audit surfaced: every
entity now has both a working edit path (preserving unmanaged tags) and owner
management.
Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
|
||
|---|---|---|
| .agents/skills | ||
| .github | ||
| .nsite | ||
| .vscode | ||
| android-templates | ||
| cvm-server | ||
| eslint-rules | ||
| public | ||
| scripts | ||
| skills | ||
| src | ||
| .gitignore | ||
| .gitlab-ci.yml | ||
| .mcp.json | ||
| .npmrc | ||
| AGENTS.md | ||
| BOUNTY-SYSTEM-PLAN.md | ||
| BUDGET_IMPLEMENTATION.md | ||
| capacitor.config.ts | ||
| components.json | ||
| CONTEXTVM_INTEGRATION.md | ||
| DEPLOYMENT_COMPARISON.md | ||
| EMERGENCY_FIX.md | ||
| eslint.config.js | ||
| FINAL_POLISH_BREAKDOWN.md | ||
| FINAL_SCOPE.md | ||
| FIXES_BREAKDOWN.md | ||
| FOLLOW_MANAGEMENT_BRIEFING.md | ||
| HOW_TO_ENABLE_RELATR.md | ||
| IMPLEMENTATION_COMPLETE.md | ||
| IMPLEMENTATION_PLAN.md | ||
| index.html | ||
| INTEGRATION_BRIEFING.md | ||
| LIVE_MUSIC_PROPOSAL.md | ||
| LOGO_USAGE.md | ||
| MCP_SERVER_SPEC.md | ||
| netlify.toml | ||
| NIP-06-IMPLEMENTATION.md | ||
| NIP.md | ||
| NOGOOD_RADIO_PROPOSAL.md | ||
| opencode.json | ||
| package-lock.json | ||
| package.json | ||
| postcss.config.js | ||
| RADIO_PLAYER_GUIDE.md | ||
| README.md | ||
| RELATR_INTEGRATION.md | ||
| RELAY_FIX.md | ||
| RELAY_SETUP.md | ||
| release-notes.txt | ||
| SECURITY.md | ||
| SHOP_VERIFICATION_ANALYSIS.md | ||
| stack.json | ||
| tailwind.config.ts | ||
| tsconfig.json | ||
| vite.config.ts | ||
| WEATHER_FEATURE.md | ||
| ZAP_INTEGRATION_PROPOSAL.md | ||
| ZAP_QUICK_WINS.md | ||
| ZAP_SIMPLE_PLAN.md | ||
| ZAPSTORE.md | ||
| zapstore.yaml | ||
SkateSpots - Decentralized Skate Map & Community
A decentralized skateboarding community platform built on Nostr. Discover skate spots, find coaches, join events, and connect with skaters worldwide.
🌐 Live App
- Deployed URL: https://skate-spots.org
- Nostr Git: nostr://npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx/git.shakespeare.diy/SkateSpots
✨ Features
- 🗺️ Interactive Skate Map - Discover skate spots worldwide with geolocation
- 🛹 Spot Database - Browse, create, and review skate parks and street spots
- 📅 Events Calendar - Find and create skateboarding events and competitions
- 👨🏫 The Lab - Connect with coaches, filmers, and video editors in your area
- 🎬 Video Editors - Find editors who list their software, hardware, and portfolio
- 🛍️ Skate Shops - Discover local skate shops and support the community
- 🔄 Buy/Sell Gear - Marketplace for used skate gear (NIP-99 classified listings)
- 🎒 My Stash - Private encrypted gear inventory with location tracking
- 🎵 NoGood Radio - 24/7 vibing music (lofi, synthwave, electronica)
- ⚡ Lightning Zaps - Send Bitcoin tips to content creators
- 🌤️ Weather Integration - Check conditions before you skate
- 🔐 Nostr Authentication - Decentralized login with your Nostr keys
- 📱 PWA Support - Install as a native app on any device
- ❤️ Supporters - Community funding via Angor (decentralized Bitcoin crowdfunding)
🛠️ Technology Stack
- React 18 - Modern UI with hooks and concurrent rendering
- Nostr Protocol - Decentralized data storage and communication
- TailwindCSS 3 - Utility-first CSS framework
- Vite - Lightning-fast build tool and dev server
- shadcn/ui - Beautiful, accessible UI components
- Nostrify - Nostr framework for web applications
- TanStack Query - Data fetching and caching
- OpenStreetMap - Interactive maps
- TypeScript - Type-safe development
🚀 Getting Started
Prerequisites
- Node.js 18+
- npm or yarn
Installation
# Clone the repository
git clone nostr://npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx/git.shakespeare.diy/SkateSpots
# Install dependencies
npm install
# Start development server
npm run dev
Building
# Build for production
npm run build
# Run tests
npm test
🌍 Deployment
The app is configured for deployment via:
- Shakespeare Deploy - Nostr-native deployment (configured)
- Netlify - Static site hosting
- Vercel - Edge deployment
- nsite - Nostr-native sites
Deploy command:
npm run deploy
📱 PWA Installation
SkateSpots works as a Progressive Web App (PWA) and can be installed on:
- Desktop: Chrome, Edge, Safari - Look for install icon in address bar
- Android: Chrome - "Add to Home Screen" from menu
- iOS: Safari - "Add to Home Screen" from share menu
🔌 Nostr Integration
Custom Event Kinds
This app uses custom Nostr event kinds defined in NIP.md:
| Kind | Type | Description |
|---|---|---|
| 30017 | Addressable | Skate Shops (NIP-15 Stall) |
| 30402 | Addressable | Gear Listings (NIP-99 Classified) |
| 30818 | Addressable | Skate Spots |
| 30823 | Addressable | Skate Tours |
| 31923 | Addressable | Skate Events (NIP-52 Calendar) |
| 35001 | Addressable | Skate Coaches |
| 35002 | Addressable | Skate Filmers / Photographers |
| 35003 | Addressable | Skate Video Editors |
Relay Configuration
Default relay: wss://goskatespots.nostr1.com
Users can manage relays in Settings following NIP-65.
🎒 My Stash
The Stash is a private, encrypted gear inventory (NIP-51 kind 30001). Users can track their equipment with:
- Categories: Decks, trucks, wheels, bearings, shoes, apparel, protective gear, and more
- Storage locations: Home, car, backpack, wardrobe, van, skatepark, friend's, parents', warehouse, storage unit, sponsor, or other
- Condition rating (1–5 stars), rarity tier, and optional price
- Visibility control: Private (encrypted), friends-only, or public
- Filter & search by category, storage location, or keyword
🧪 The Lab
The Lab connects skaters with service providers in three categories:
- Coaches - Skateboarding instructors with skill specializations
- Filmers - Videographers and photographers with equipment/style details
- Video Editors - Editors who list their software (Premiere, DaVinci, After Effects, etc.), hardware setup, portfolio, and contact details
📦 Dependencies Overview
Core Dependencies
@nostrify/nostrify- Nostr protocol implementation@nostrify/react- React integration for Nostrreact&react-dom- UI frameworkreact-router-dom- Client-side routing@tanstack/react-query- Data fetching and statenostr-tools- Nostr utilities and cryptography
UI & Styling
tailwindcss- Utility-first CSS@radix-ui/*- Accessible UI primitiveslucide-react- Icon libraryclass-variance-authority- Component variantstailwind-merge- Class name merging
Maps & Location
- OpenStreetMap - Interactive maps
ngeohash- Geohash encoding/decoding
Bitcoin & Lightning
@getalby/sdk- Alby wallet integration@cashu/cashu-ts- Cashu ecash protocolnpubcash-sdk- npub.cash integrationbitcoinjs-lib- Bitcoin utilities@noble/curves&@noble/hashes- Cryptography
Media & Streaming
hls.js- HLS streaming supportqrcode- QR code generationhtml5-qrcode- QR code scanning
Utilities
date-fns- Date formattingzod- Schema validationreact-hook-form- Form handlingbuffer- Node.js buffer polyfillidb&dexie- IndexedDB wrappers
🏗️ Project Structure
/src
├── components/ # React components
│ ├── ui/ # shadcn/ui components (48+)
│ ├── auth/ # Authentication components
│ └── ... # Feature components
├── hooks/ # Custom React hooks
├── pages/ # Route pages
├── lib/ # Utilities and helpers
├── contexts/ # React context providers
└── test/ # Testing utilities
/public
├── images/ # Static images and icons
├── manifest.webmanifest
└── robots.txt
/skills # Implementation guides for features
🧪 Testing
# Run all tests (TypeScript, ESLint, Vitest, Build)
npm test
# Type checking only
npx tsc --noEmit
# Linting only
npx eslint
🤝 Contributing
This is a Nostr-based open source project. Contributions are welcome!
- Fork/clone the repository via Shakespeare or git
- Create your feature branch
- Make your changes
- Run tests (
npm test) - Commit your changes
- Push and create a pull request
📄 License
YOU ARE FREE TO SKATEBOARD
This project is open. Share it, fork it, build on it, skate it. The streets belong to everyone. So does this code. Just keep skating and don't be a kook.
Copyright © 2025–∞ SkateSpots contributors & the community
See /license in the app for the full license page.
❤️ Support the Project
SkateSpots is 100% free, open-source, and community-funded. No ads, no data selling, no investors.
- Angor: https://angor.io/project/angor1qtunna00uqyx52rr0nvqa059z2gknhrmn7urd6z
- Supporters page: https://skate-spots.org/supporters
🙏 Credits
- Built with: MKStack - Nostr client framework
- Vibed with: Shakespeare - AI-powered development
- Powered by: Nostr - Decentralized protocol
- Funded by: Angor - Decentralized Bitcoin crowdfunding
🔗 Links
📞 Support
For issues or questions:
- Open an issue on the repository
- Contact via Nostr: npub1yrnuj56rnen08zp2h9h7p74ghgjx6ma39spmpj6w9hzxywutevsst7k5cx
Made with ❤️ for the skateboarding community