A complete location-based social feed generator built on the AT Protocol for decentralized social networking.
The system consists of 3 main components:
- Ingestion - Real-time check-in data ingestion from AT Protocol Jetstream
- API - Feed APIs for global, nearby, user, and following feeds
- Social - Social graph sync from Bluesky for following feeds
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
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
# 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
# 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.
Base URL: https://anchor-feed-generator.val.run
GET https://anchor-feed-generator.val.run/global?limit=50&cursor=2025-06-29T15:00:00Z
Recent check-ins from all users with pagination.
GET https://anchor-feed-generator.val.run/nearby?lat=52.0705&lng=4.3007&radius=5&limit=50
Spatial query for check-ins within specified radius (km).
GET https://anchor-feed-generator.val.run/user?did=did:plc:abc123&limit=50
All check-ins from a specific user.
GET https://anchor-feed-generator.val.run/following?user=did:plc:abc123&limit=50&cursor=2025-06-29T15:00:00Z
Check-ins from people the specified user follows on Bluesky.
GET https://anchor-feed-generator.val.run/stats
AppView health metrics and processing statistics.
For complete API documentation including examples, data models, and SDK code samples, see:
The system uses 5 main SQLite tables:
checkins_v1
- Main check-ins with coordinates and cached address dataaddress_cache_v1
- Resolved venue/address information from strongrefsprofile_cache_v1
- Cached user profile data (display names, avatars)user_follows_v1
- Social graph data for following-based feedsprocessing_log_v1
- Monitoring and operational logging
- 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
The project includes comprehensive tests for all components:
Unit Tests:
profile-resolver.test.ts
- Profile caching, resolution, and refresh logichandle-resolver.test.ts
- Handle resolution from DIDsaddress-cache.test.ts
- Address caching and resolutiondatabase.test.ts
- Database operationsspatial.test.ts
- Spatial calculationsjetstream-ingestion.test.ts
- Event ingestion
Integration Tests:
api-profiles.test.ts
- API endpoints with profile data includedapi.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
- 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
- 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
- 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
- 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
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
This implementation is part of the Anchor project for location-based social networking on the AT Protocol.