FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
tijs
tijslocation-feed-generator
This is the Anchor AppView - location based feed generator
Public
Like
1
location-feed-generator
Home
Code
19
.claude
1
.github
1
backend
9
coverage
database
2
docs
2
frontend
5
shared
static
tests
4
.gitignore
.vtignore
ATProto-OAuth-Guide.md
CLAUDE.md
README.md
deno.json
deno.test.json
H
main.tsx
opinionated-val-town.md
Branches
1
Pull requests
Remixes
History
Environment variables
7
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
README.md
Code
/
README.md
Search
8/13/2025
Viewing readonly version of main branch: v697
View latest version
README.md

Anchor AppView

A complete location-based social feed generator and web interface built on the AT Protocol for decentralized social networking. Provides both API endpoints for mobile clients and a web interface for viewing and sharing check-ins.

šŸ—ļø Architecture

The system consists of 4 main components:

  • Ingestion - Real-time check-in data ingestion from AT Protocol Jetstream
  • API - RESTful APIs for global, nearby, user, and following feeds
  • Web Interface - React-based web frontend for viewing feeds and shareable checkin detail pages
  • Social - Social graph sync from Bluesky for following feeds

šŸ“ Project Structure

src/
ā”œā”€ā”€ ingestion/          # Data ingestion from AT Protocol
│   └── jetstream-poller.ts
ā”œā”€ā”€ api/               # HTTP API endpoints
│   └── anchor-api.ts
ā”œā”€ā”€ social/            # Social graph management
│   └── social-graph-sync.ts
└── utils/             # Shared utilities
    ā”œā”€ā”€ handle-resolver.ts
    ā”œā”€ā”€ address-resolver.ts
    ā”œā”€ā”€ address-cache.ts    # Val Town blob storage cache
    ā”œā”€ā”€ profile-resolver.ts # Profile caching and resolution
    └── profile-refresh-job.ts # Background profile refresh

frontend/
ā”œā”€ā”€ main.tsx           # React app entry point and routing
ā”œā”€ā”€ components/        # React components
│   ā”œā”€ā”€ CheckinDetail.tsx  # Individual checkin detail view with map
│   ā”œā”€ā”€ Feed.tsx          # Global feed component
│   └── Layout.tsx        # App layout and navigation
└── types/
    └── index.ts       # TypeScript type definitions

database/
ā”œā”€ā”€ database-schema.sql # SQLite schema and indexes
└── add-profile-cache.sql # Profile cache migration

docs/
ā”œā”€ā”€ api-documentation.md # Complete API reference for client development
└── deployment-guide.md  # Deployment instructions

scripts/
ā”œā”€ā”€ deploy.sh          # One-click deployment script
ā”œā”€ā”€ test.sh            # Run complete test suite
ā”œā”€ā”€ debug.ts           # Debug data availability and API status
└── monitor-api.sh     # Monitor deployed API status

tests/
ā”œā”€ā”€ unit/              # Unit tests for individual functions
│   ā”œā”€ā”€ handle-resolver.test.ts
│   ā”œā”€ā”€ profile-resolver.test.ts  # Profile caching and resolution
│   ā”œā”€ā”€ address-cache.test.ts
│   ā”œā”€ā”€ database.test.ts
│   └── spatial.test.ts
ā”œā”€ā”€ integration/       # Integration tests for API endpoints
│   ā”œā”€ā”€ api.test.ts
│   └── api-profiles.test.ts      # API endpoints with profile data
└── fixtures/          # Test data and fixtures
    └── test-data.ts

šŸš€ Quick Start

Option 1: One-Click Deployment

# Install Val Town CLI npm install -g @valtown/cli # Login to Val Town vt login # Run tests first ./scripts/test.sh # Deploy all functions ./scripts/deploy.sh # Monitor the deployment ./scripts/monitor-api.sh

Option 2: Manual Deployment

# Deploy individual functions vt create cron jetstreamPoller --file src/ingestion/jetstream-poller.ts --schedule "*/5 * * * *" vt create http anchorAPI --file src/api/anchor-api.ts vt create cron socialGraphSync --file src/social/social-graph-sync.ts --schedule "0 2 * * *"

Note: No manual database setup required! Tables are created automatically when functions first run.

šŸ”Œ API Endpoints

Base URL: https://dropanchor.app

Feed APIs

Global Feed

GET https://dropanchor.app/api/global?limit=50&cursor=2025-06-29T15:00:00Z

Recent check-ins from all users with pagination.

Nearby Checkins

GET https://dropanchor.app/api/nearby?lat=52.0705&lng=4.3007&radius=5&limit=50

Spatial query for check-ins within specified radius (km).

User Checkins

GET https://dropanchor.app/api/user?did=did:plc:abc123&limit=50

All check-ins from a specific user.

Following Feed

GET https://dropanchor.app/api/following?user=did:plc:abc123&limit=50&cursor=2025-06-29T15:00:00Z

Check-ins from people the specified user follows on Bluesky.

Individual Checkin

Checkin Detail API

GET https://dropanchor.app/api/checkin/{rkey}

Individual checkin data by record key for detail views and sharing.

System APIs

Statistics

GET https://dropanchor.app/api/stats

AppView health metrics and processing statistics.

🌐 Web Interface

Public Web Pages

Global Feed

https://dropanchor.app/

Web interface showing the global feed of check-ins.

Shareable Checkin Details

https://dropanchor.app/checkin/{rkey}

Individual checkin detail page with interactive map, optimized for sharing on social media with Open Graph meta tags.

šŸ“š API Documentation

For complete API documentation including examples, data models, and SDK code samples, see:

šŸ“– API Documentation

šŸ“Š Database Schema

The system uses 5 main SQLite tables:

  • checkins_v1 - Main check-ins with coordinates and cached address data
  • address_cache_v1 - Resolved venue/address information from strongrefs
  • profile_cache_v1 - Cached user profile data (display names, avatars)
  • user_follows_v1 - Social graph data for following-based feeds
  • processing_log_v1 - Monitoring and operational logging

🌟 Key Features

Backend Features

  • Real-time Ingestion: WebSocket polling every 5 minutes from Jetstream
  • Address Resolution: Automatic strongref resolution with caching
  • Profile Resolution: Automatic profile data fetching and caching
  • Spatial Queries: Nearby check-ins using Haversine distance calculations
  • Social Integration: Following feeds leveraging Bluesky's social graph
  • Performance: SQLite with proper indexing for fast queries
  • Error Handling: Comprehensive error tracking and retry logic

Web Interface Features

  • Global Feed View: Browse all check-ins with author profiles and timestamps
  • Shareable Checkin Pages: Individual checkin detail pages with interactive maps
  • Interactive Maps: OpenStreetMap integration via Leaflet with CartoDB tiles
  • Social Sharing: Optimized sharing with Web Share API and copy functionality
  • Responsive Design: Mobile-friendly interface using system fonts
  • Open Graph Tags: Rich social media previews for shared checkin URLs

šŸ”§ Development

Known Technical Debt

  • Share URL Collisions: Currently using AT Protocol rkeys as unique identifiers in share URLs (/checkin/{rkey}). While collision risk is negligible at current scale (~32 simultaneous checkins per microsecond for 50% collision probability), rkeys only provide 10 bits of entropy and are not cryptographically guaranteed to be globally unique. Consider migrating to composite identifiers (DID+rkey) or backend-generated UUIDs if collision issues emerge at scale.

Testing

The project includes comprehensive tests for all components:

Unit Tests:

  • profile-resolver.test.ts - Profile caching, resolution, and refresh logic
  • handle-resolver.test.ts - Handle resolution from DIDs
  • address-cache.test.ts - Address caching and resolution
  • database.test.ts - Database operations
  • spatial.test.ts - Spatial calculations
  • jetstream-ingestion.test.ts - Event ingestion

Integration Tests:

  • api-profiles.test.ts - API endpoints with profile data included
  • api.test.ts - Core API functionality
# Run all tests ./scripts/test.sh # Run specific test suites deno test --allow-all tests/unit/ # Unit tests only deno test --allow-all tests/integration/ # Integration tests only # Run tests in watch mode ./scripts/test.sh --watch # Run with coverage ./scripts/test.sh --coverage

Val Town Best Practices

  • Use TypeScript for all functions
  • Import SQLite: import { sqlite } from "https://esm.town/v/stevekrouse/sqlite"
  • Import blob storage: import { blob } from "https://esm.town/v/std/blob"
  • Use https://esm.sh for external dependencies
  • Never hardcode secrets - use Deno.env.get('keyname')
  • Let errors bubble up with full context rather than catching and logging

Data Storage Strategy

  • SQLite: Primary data (checkins, social graph, processing logs)
  • Blob Storage: Caching layer for address resolution with automatic expiry
  • Schema Changes: Increment table versions (e.g., checkins_v1 → checkins_v2)
  • Always create tables with IF NOT EXISTS on function startup

šŸ“ˆ Monitoring

  • Monitor /stats endpoint for system health
  • Check processing_log_v1 for ingestion metrics
  • Use built-in logging and debugging tools
  • Monitor SQLite performance as data grows

šŸ”’ Security

  • All API endpoints include proper CORS headers
  • Public APIs only - no authentication required
  • Rate limiting built into external service calls
  • No sensitive data logged or stored

🌐 AT Protocol Integration

The AppView is fully compatible with the AT Protocol ecosystem:

  • Ingests from Jetstream (official AT Protocol firehose)
  • Resolves DIDs using PLC directory
  • Fetches records via com.atproto.repo.getRecord
  • Integrates with Bluesky social graph APIs

šŸ“„ License

This implementation is part of the Anchor project for location-based social networking on the AT Protocol.

Go to top
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Product
FeaturesPricing
Developers
DocsStatusAPI ExamplesNPM Package Examples
Explore
ShowcaseTemplatesNewest ValsTrending ValsNewsletter
Company
AboutBlogCareersBrandhi@val.town
Terms of usePrivacy policyAbuse contact
Ā© 2025 Val Town, Inc.