From f0d546e622321f161ee15454ebac0163d5cccfe8 Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 7 Sep 2026 19:52:25 -0500 Subject: [PATCH] docs: rewrite the README for the codebase as it is now The old one listed every route and every file, half of which had been renamed or deleted, and named Headless UI and Lucide as the UI stack. The new one says what the app does, how to run and check it, how the tree is laid out, and the four things a contributor has to know: contract topology, document ownership, the unconfirmed-write gate, and storage scoping. --- README.md | 428 +++++++++--------------------------------------------- 1 file changed, 65 insertions(+), 363 deletions(-) diff --git a/README.md b/README.md index 232e6679..91805c94 100644 --- a/README.md +++ b/README.md @@ -1,395 +1,97 @@ # Yappr -A decentralized social media platform and marketplace built on Dash Platform. All data—posts, profiles, likes, follows, bookmarks, mentions, tips, direct messages, stores, and orders—is stored on-chain with full user ownership. +A decentralized social network and marketplace on Dash Platform. Posts, profiles, likes, follows, bookmarks, direct messages, private feeds, blogs, polls, stores and orders are all documents on chain, owned by the identity that wrote them. There is no server: the site is a static export that talks to Dash Platform directly from the browser. -Yappr Screenshot +Yappr -## Features +Live at [yap.pr](https://yap.pr). A second copy at [yap.pr/testing](https://yap.pr/testing/) runs the same code against dedicated test contracts and is what the end-to-end suite drives; [yap.pr/devnet](https://yap.pr/devnet/) tracks the newest contract shape. -### Core Social -- **Posts**: 500-character posts with optional links and media -- **Replies & Threads**: Nested conversation threads with quote posts -- **Likes & Reposts**: Engage with posts -- **Follows**: Follow users to see their posts in your feed -- **Bookmarks**: Save posts to your bookmarks (stored on-chain) -- **Direct Messages**: Encrypted point-to-point messaging with conversation threading -- **Mentions**: Tag users with @username in posts -- **Blocking**: Block users to prevent interactions, subscribe to others' block lists -- **DashPay Contacts**: Import and interact with DashPay contacts +## What it does -### Private Feeds -- **Encrypted Private Posts**: Followers-only content with XChaCha20-Poly1305 encryption -- **Private Feed Grants**: Grant specific users access to your private posts -- **Epoch-Based Key Derivation**: Efficient key management for content access -- **Follow Revocation**: Remove followers and automatically rekey private content -- **Private Feed Requests**: Request access to users' private feeds +- **Social**: 500-character posts with media, replies and threads, quotes, likes, reposts, follows, bookmarks, blocking (with shared block lists), @mentions and #hashtags, an explore page with trending tags and ranked posts. +- **Private feeds**: followers-only posts encrypted with XChaCha20-Poly1305, epoch-based key derivation, grant and revoke without re-uploading content. See `docs/YAPPR_PRIVATE_FEED_SPEC.md` and `/about/private-feeds`. +- **Direct messages**: end-to-end encrypted, on a separate contract. +- **Blogs**: long-form posts with a block editor, chunked on chain, embeddable in the feed. +- **Polls**: native polls on the Pollr contract, embedded in posts. +- **Storefront**: stores, items with variants, cart, checkout with shipping zones, encrypted orders, order status, reviews, encrypted saved addresses. +- **Payments**: tips by QR code, payment URIs for Dash and other coins, YAPP token purchases that pay for writes. +- **Identity**: self-custodied keys, DPNS usernames, optional password-encrypted on-chain key backup, passkey unlock, wallet sign-in through key exchange. -### Discovery -- **Hashtags**: Tag posts with #hashtags, browse trending topics -- **Explore Page**: Trending hashtags and popular posts -- **User Search**: Find users by DPNS username or identity ID -- **Mentions Feed**: View all posts that mention you - -### Storefront / Marketplace -- **Create Stores**: Set up your merchant storefront with branding -- **Product Listings**: Add items with variants, categories, images, and pricing -- **Shopping Cart**: Add items from multiple stores -- **Checkout Flow**: Address entry, shipping calculation, payment selection -- **Encrypted Orders**: Order data encrypted so only buyer and seller can read -- **Order Management**: Track orders as buyer, manage incoming orders as seller -- **Shipping Zones**: Configure flat, weight-tiered, or price-tiered shipping -- **Store Reviews**: Leave reviews with 1-5 star ratings after purchase -- **Saved Addresses**: Encrypted saved shipping addresses - -### User Experience -- **Dark/Light Theme**: System-aware with manual override -- **Mobile-First**: Responsive design with bottom navigation on mobile -- **DiceBear Avatars**: Unique thumbs-style avatars based on identity -- **DPNS Integration**: Human-readable usernames via Dash Platform Name Service -- **Link Previews**: Rich previews for shared links -- **Notifications**: Real-time notifications for likes, follows, replies, mentions, and private feed events -- **Testnet Banner**: Visual indicator when running on testnet - -### Payments & Tips -- **Tips**: Send tips to users via QR code (Dash and other crypto addresses) -- **Payment QR Codes**: Generate payment requests with amount and message -- **Multi-Currency Support**: USD, EUR, DASH, and other currencies -- **Payment URIs**: Support for dash:, bitcoin:, and other payment protocols - -### Security -- **Self-Custody**: You control your private keys -- **Encrypted Key Backup**: Optional on-chain encrypted backup with password protection -- **Session Storage**: Secure key storage for browser sessions -- **No Central Database**: All data stored on Dash Platform - -## Tech Stack - -| Category | Technology | -|----------|------------| -| Framework | Next.js 14 (App Router, Static Export) | -| Language | TypeScript | -| Blockchain | Dash Platform via @dashevo/evo-sdk | -| Styling | Tailwind CSS | -| UI Components | Radix UI, Headless UI | -| Animations | Framer Motion | -| State | Zustand | -| Icons | Heroicons, Lucide React | -| Theming | next-themes | -| Dates | date-fns | -| Crypto | @noble/hashes, @noble/secp256k1 | -| QR Codes | qrcode.react | -| Toasts | react-hot-toast | -| Encoding | bs58, bs58check | - -## Getting Started +## Getting started ```bash -# Install dependencies npm install +npm run dev # http://localhost:3000 +``` -# Start development server -npm run dev +Everything the app needs is in the browser; there is nothing else to run. Contract ids and the network live in `lib/constants.ts` and can be overridden with `NEXT_PUBLIC_*` variables. -# Build for production -npm run build +| Command | What it does | +|---------|--------------| +| `npm run build` | Production static export into `out/` | +| `npm run build:subpath` | The same, for a `/yappr` sub-path (GitHub Pages) | +| `npm run build:testing` | Export against the test contracts in `.env.testing` under `/testing` | +| `npm run build:devnet` | Export against `.env.devnet` under `/devnet` | +| `npm run lint` | ESLint over `app components contexts hooks lib types`; warnings fail | +| `npm run test` | Vitest specs next to the pure modules in `lib/` | +| `npm run lint:dead` | knip: unused files, exports and dependencies | +| `npm run test:e2e` | Playwright against the `/testing` export on real testnet (see `docs/TESTING.md`) | -# Build for a sub-path deployment (e.g. GitHub Pages) -npm run build:subpath +CI runs lint, type check, unit tests, knip and the build on every pull request; the end-to-end suite runs when the secrets are present. -# Run linting -npm run lint -``` +## How it is built -Open [http://localhost:3000](http://localhost:3000) in your browser. +| | | +|---|---| +| Framework | Next.js 14 App Router, `output: 'export'`, no dynamic routes (query parameters instead) | +| Chain | `@dashevo/evo-sdk` + `@dashevo/wasm-sdk`, trusted mode, direct DAPI | +| Crypto | `@noble/hashes`, `@noble/ciphers`, `@noble/secp256k1` | +| UI | Tailwind, Radix primitives, Framer Motion, Heroicons, Zustand | +| Editor | BlockNote for blogs | -## Project Structure +### Layout ``` -yappr/ -├── app/ # Next.js pages (App Router) -│ ├── about/ # About page -│ ├── bookmarks/ # Saved posts -│ ├── cart/ # Shopping cart -│ ├── checkout/ # Checkout flow -│ ├── contract/ # View data contract JSON -│ ├── cookies/ # Cookie policy -│ ├── dpns/register/ # Register DPNS username -│ ├── explore/ # Trending hashtags and posts -│ ├── feed/ # Main feed (Following / For You) -│ ├── followers/ # User's followers list -│ ├── following/ # User's following list -│ ├── hashtag/ # Posts by hashtag -│ ├── login/ # Authentication -│ ├── mentions/ # Posts mentioning a user -│ ├── messages/ # Direct messages -│ ├── notifications/ # User notifications -│ ├── orders/ # Buyer order history -│ ├── orders/seller/ # Seller order management -│ ├── post/ # Post detail view and threads -│ ├── privacy/ # Privacy policy -│ ├── profile/create/ # Profile creation -│ ├── search/ # Search users and hashtags -│ ├── settings/ # User settings -│ ├── store/ # Store listing and storefront views -│ ├── store/create/ # Create new store -│ ├── store/item/add/ # Add items to store -│ ├── store/manage/ # Manage store settings -│ ├── store/view/ # View store details -│ ├── terms/ # Terms of service -│ └── user/ # View other user's profile -│ -├── components/ -│ ├── auth/ # Key backup and password modals -│ ├── compose/ # Post composition modal -│ ├── contacts/ # DashPay contacts integration -│ ├── dpns/ # DPNS username components -│ ├── home/ # Homepage sections (stats, featured, top users) -│ ├── layout/ # Sidebar, mobile nav, right sidebar -│ ├── post/ # Post card, content renderer, likes modal -│ ├── profile/ # Profile card, edit forms -│ ├── search/ # Search components -│ ├── settings/ # Settings components -│ ├── store/ # Store components (cart, checkout, items) -│ ├── ui/ # Core UI primitives (button, input, avatar, etc.) -│ ├── error-boundary.tsx # Error boundary wrapper -│ └── providers.tsx # App providers (theme, SDK, auth) -│ -├── contexts/ -│ ├── auth-context.tsx # Authentication state and user session -│ └── sdk-context.tsx # Dash SDK context provider -│ -├── hooks/ # Custom React hooks -│ ├── use-avatar.ts # Avatar generation and caching -│ ├── use-block.ts # Block/unblock functionality -│ ├── use-can-reply-to-private.ts # Check private post reply access -│ ├── use-dashpay-contacts-modal.ts # DashPay contacts modal -│ ├── use-dpns-registration.ts # DPNS name registration -│ ├── use-encryption-key-modal.ts # Encryption key modal -│ ├── use-follow.ts # Follow/unfollow actions -│ ├── use-homepage-data.ts # Homepage stats aggregation -│ ├── use-link-preview.ts # Link preview fetching -│ ├── use-login-modal.ts # Login modal -│ ├── use-post-field-validation.ts # Hashtag/mention index checks -│ ├── use-post-detail.ts # Post detail with thread loading -│ ├── use-post-enrichment.ts # Post stats with deduplication -│ ├── use-private-feed-request.ts # Private feed access requests -│ ├── use-progressive-enrichment.ts # Progressive data loading -│ ├── use-require-auth.ts # Auth requirement wrapper -│ └── use-tip-modal.ts # Tip/payment modal -│ -├── lib/ -│ ├── services/ # Dash Platform service layer -│ │ ├── avatar-generator.ts # DiceBear avatar generation -│ │ ├── block-service.ts # User blocking -│ │ ├── bookmark-service.ts # Bookmarks -│ │ ├── dashpay-contacts-service.ts # DashPay contacts -│ │ ├── direct-message-service.ts # Encrypted DMs -│ │ ├── document-service.ts # Query operations -│ │ ├── dpns-service.ts # Username resolution -│ │ ├── encrypted-key-service.ts # On-chain key backup -│ │ ├── evo-sdk-service.ts # SDK connection management -│ │ ├── follow-service.ts # Follows -│ │ ├── hashtag-service.ts # Hashtag tracking & trending -│ │ ├── hashtag-validation-service.ts # Hashtag validation -│ │ ├── identity-service.ts # Identity & balance queries -│ │ ├── key-validation-service.ts # Private key validation -│ │ ├── like-service.ts # Likes -│ │ ├── mention-service.ts # Mentions -│ │ ├── mention-validation-service.ts # Mention validation -│ │ ├── notification-service.ts # Notifications -│ │ ├── pagination-utils.ts # Pagination helpers -│ │ ├── post-service.ts # Posts CRUD -│ │ ├── private-feed-service.ts # Private feed management -│ │ ├── private-feed-follower-service.ts # Private feed grants -│ │ ├── private-feed-crypto-service.ts # Private feed encryption -│ │ ├── private-feed-key-store.ts # Private feed key storage -│ │ ├── profile-service.ts # Profile management -│ │ ├── reply-service.ts # Reply operations -│ │ ├── repost-service.ts # Reposts -│ │ ├── saved-address-service.ts # Saved shipping addresses -│ │ ├── sdk-helpers.ts # SDK utility functions -│ │ ├── state-transition-service.ts # Write operations -│ │ ├── store-service.ts # Store management -│ │ ├── store-item-service.ts # Store items -│ │ ├── store-order-service.ts # Order management -│ │ ├── store-review-service.ts # Store reviews -│ │ ├── tip-service.ts # Tip/payment handling -│ │ ├── unified-profile-service.ts # Unified profile queries -│ │ └── index.ts # Service exports -│ ├── stores/ # Zustand stores -│ │ ├── notification-store.ts # Notification state -│ │ └── private-feed-refresh-store.ts # Private feed state -│ ├── caches/ # Client-side caching -│ │ ├── block-cache.ts # Block list cache -│ │ └── user-status-cache.ts # User status cache -│ ├── crypto/ # Cryptographic utilities -│ │ ├── hash.ts # Hashing functions -│ │ ├── key-derivation.ts # Epoch key derivation -│ │ ├── keys.ts # Key operations -│ │ └── wif.ts # WIF encoding/decoding -│ ├── bloom-filter.ts # Bloom filter for efficient lookups -│ ├── cache-manager.ts # Query caching -│ ├── constants.ts # Contract IDs, network config -│ ├── error-utils.ts # Error handling utilities -│ ├── message-encryption.ts # DM encryption -│ ├── mock-data.ts # Default placeholder avatar -│ ├── onchain-key-encryption.ts # Key backup encryption -│ ├── post-helpers.ts # Post utility functions -│ ├── retry-utils.ts # Retry logic with backoff -│ ├── secure-storage.ts # Session storage for keys -│ ├── store.ts # Main Zustand store -│ ├── types.ts # TypeScript interfaces (re-exports types/) -│ └── utils/ # Helper functions -│ -├── types/ # Domain types: user, post, store, notification -│ -├── contracts/ # Dash Platform data contracts -│ ├── yappr-social-contract-v2.json # Main social contract (staging/prod) -│ ├── yappr-social-contract-v5.json # Devnet social contract (v5 topology) -│ ├── yappr-social-contract-v4.json # Superseded devnet shape; input to build-v5-contract.py -│ ├── yappr-storefront-contract.json # Stores, items, orders, reviews -│ ├── yappr-dm-contract.json # Direct messages -│ ├── yappr-hashtag-contract.json # Legacy - merged into the social contract -│ ├── yappr-mention-contract.json # Legacy - merged into the social contract -│ ├── yappr-block-contract.json # Legacy - merged into the social contract -│ ├── yappr-profile-contract.json # Unified profile contract -│ ├── encrypted-key-backup-contract.json # Key backup -│ └── README.md # Contract documentation -│ -├── public/ # Static assets -│ ├── yappr.png # App logo -│ ├── yappr.jpg # App logo (JPEG) -│ ├── pbde-dark.png # "Powered by Dash Evo" dark -│ └── pbde-light.png # "Powered by Dash Evo" light -│ -├── .github/workflows/ # CI/CD workflows -│ ├── ci.yml # Lint, typecheck, build on PR -│ └── deploy.yml # Deploy to GitHub Pages -│ -├── next.config.js # Next.js configuration (static export, WASM) -├── tailwind.config.js # Tailwind CSS configuration -└── docs/archive/TODO-MAINNET.md # Pre-mainnet task tracking +app/ one folder per route; query params carry ids (/post?id=…) +components/ by feature: post, compose, profile, feed, store, blog, poll, auth, settings, layout, ui +hooks/ React hooks; the *-modal hooks are zustand stores built by lib/modal-store.ts +contexts/ auth (wraps the vendored platform-auth controller) and SDK readiness +lib/ + services/ singleton services per document type; all reads and writes go through here + feed/ feed loaders and post resolution (quotes, reply parents, reposts) + compose/ turning a draft thread into documents + link-preview/ URL recognition, HTML meta parsing, proxied fetch + crypto/ AES-GCM, ECDH, WIF, identity-key matching, vault + caches/ TtlMap and the status caches the hooks share + stores/ app-wide zustand stores + contract-topology.ts which contract shape this build targets and what it allows + constants.ts contract ids and network +types/ domain types +contracts/ the deployed data contracts (JSON); older shapes are kept for reference +vendor/ platform-auth, the shared login controller +e2e/ Playwright: smoke (read-only) and write (needs E2E_SEED_PHRASE) +docs/ private-feed spec, testing guide, deployment runbooks ``` -## Dash Platform Integration - -Yappr uses multiple data contracts deployed on Dash Platform (testnet): - -### Main Social Contract -Core social features with 16 document types: -- `profile` - Display name, bio, location, website -- `post`, `reply` - Text posts (500 char limit), with optional private encryption -- `like`, `repost`, `follow`, `followRequest` - Social interactions -- `bookmark` - Collections -- `block`, `blockFilter`, `blockFollow` - User preferences and moderation -- `postHashtag`, `postMention` - Discovery indexes -- `privateFeedGrant`, `privateFeedRekey`, `privateFeedState` - Private feed key management - -Notifications are derived client-side rather than stored; direct messages use the separate DM contract. - -### Storefront Contract -Full e-commerce functionality: -- `store` - Merchant store profile with branding and policies -- `storeItem` - Product listings with variants, categories, and pricing -- `shippingZone` - Shipping rate configurations (flat, weight-tiered, price-tiered) -- `storeOrder` - Encrypted orders (only buyer and seller can decrypt) -- `orderStatusUpdate` - Order status history (pending → shipped → delivered) -- `storeReview` - Buyer reviews with 1-5 star ratings -- `savedAddress` - Encrypted saved shipping addresses - -### Direct Message Contract -- `directMessage` - Encrypted messages with conversation threading - -### Retired standalone contracts -The hashtag, mention, and block contracts no longer exist as separate deployments — -`postHashtag`, `postMention`, `block`, `blockFilter`, and `blockFollow` are now doctypes in -the main social contract, and their contract IDs have been removed from `lib/constants.ts`. -The JSON files remain in `contracts/` for history only. - -### Unified Profile Contract -- Combined profile data with additional fields - -### Encrypted Key Backup Contract -- `encryptedKeyBackup` - Password-encrypted private keys stored on-chain - -### DashPay Contract -- Integration with DashPay contacts system - -### Important: Document Ownership -Documents use `$ownerId` (automatic platform field) for ownership. Do not include custom `authorId` or `userId` fields when creating documents. - -## Routes - -| Route | Description | -|-------|-------------| -| `/` | Public homepage with platform stats | -| `/about` | About Yappr | -| `/login` | Authentication | -| `/feed` | Main feed (requires auth) | -| `/explore` | Trending hashtags and posts | -| `/search?q=xxx` | Search users and hashtags | -| `/hashtag?tag=xxx` | Posts with specific hashtag | -| `/mentions?user=xxx` | Posts mentioning a user | -| `/bookmarks` | Saved posts (requires auth) | -| `/messages` | Direct messages (requires auth) | -| `/notifications` | Notifications (requires auth) | -| `/post?id=xxx` | Post detail and thread | -| `/profile` | Current user profile (requires auth) | -| `/user?id=xxx` | User lookup by ID | -| `/followers?id=xxx` | User's followers list | -| `/following?id=xxx` | User's following list | -| `/settings` | User settings (requires auth) | -| `/dpns/register` | Register DPNS username | -| `/store` | Browse stores | -| `/store/create` | Create a new store (requires auth) | -| `/store/view?id=xxx` | View store details and items | -| `/store/manage` | Manage your store (requires auth) | -| `/store/item/add` | Add items to your store (requires auth) | -| `/cart` | Shopping cart | -| `/checkout` | Checkout flow (requires auth) | -| `/orders` | View your order history (requires auth) | -| `/orders/seller` | Manage incoming orders (requires auth) | -| `/contract` | View data contract JSON | -| `/privacy` | Privacy policy | -| `/terms` | Terms of service | -| `/cookies` | Cookie policy | - -## Architecture Notes +### Contract topology -### Fully Static Export -The app is configured for static export (`output: 'export'` in `next.config.js`). There is no backend server—all data operations go through Dash Platform DAPI directly from the client. +The social contract has been re-cut several times as Platform gained features (v2 on testnet and production; v5 and v6 on devnet with proved rankings and a beat doctype). `lib/contract-topology.ts` answers questions like "can a reply be reposted here" and "is the hashtag inline on the post", and everything that differs between shapes dispatches on it rather than on a version string. `/about` prints the topology a build was compiled with; the e2e suite checks it. -### WebAssembly Support -The Dash SDK requires WebAssembly. The app includes: -- Webpack configuration for async WASM loading -- Required security headers (COEP, COOP) for cross-origin isolation -- Bundle splitting for the Dash SDK +### Documents -### Services Layer -All Dash Platform operations go through singleton services in `lib/services/`. This provides: -- Centralized connection management -- Query caching and deduplication -- Consistent error handling -- Clean separation from UI components +Ownership is the platform's `$ownerId`; documents never carry their own author field. Notifications are derived client-side from other documents, not stored. Deletes are tombstones where the shape makes posts permanent. -### Caching -- Query cache: 2-minute TTL -- Trending cache: 5-minute TTL -- Automatic cache invalidation on writes -- Block list cached for efficient filtering +### Writes -### Known Issues -`wait_for_state_transition_result` often times out (504) even when transactions succeed. The app handles this by assuming success if broadcast succeeded but confirmation wait times out. +`lib/services/state-transition-service.ts` signs and broadcasts every write. DAPI's confirmation wait often times out even when the transition landed, so the app treats a successful broadcast as success, records the document as unconfirmed, and settles that record before anything references it (`lib/unconfirmed-writes.ts`). -## CI/CD +### Storage in the browser -The project uses GitHub Actions for continuous integration: -- **CI Workflow** (`ci.yml`): Runs on PRs to master - linting, type checking, and build verification -- **Deploy Workflow** (`deploy.yml`): Deploys to GitHub Pages on push to master +The private key lives in session storage for the tab; session metadata and preferences in local storage. Every sub-path build (`/testing`, `/devnet`, `/staging`) prefixes its keys with its own scope so deployments sharing an origin never read each other's sessions (`lib/storage-scope.ts`). `/cookies` describes this to users. -## Network +## Contributing -Currently deployed on **Dash Platform Testnet**. See `lib/constants.ts` for contract IDs and network configuration. +Run `npm run lint`, `npm run test`, `npm run lint:dead` and `npm run build` before opening a pull request; CI enforces all four. Pure modules under `lib/` get a Vitest spec beside them. Anything that needs the SDK or a browser belongs in `e2e/`. See `CLAUDE.md` for the conventions the codebase follows. ## License