Social Annotations in the Atmosphere
Testing Guide#
Running Tests#
Integration Tests#
cd server
go test ./internal/service -v
Manual Testing Checklist#
Setup#
- Enter Nix shell:
nix develop(from repo root) - Download dependencies:
cd server && go mod download - Start server:
cd server && go run cmd/server/main.go - Verify server starts: Should see "Server starting on :8080"
- Health check:
curl http://localhost:8080/health - Expected:
{"status":"healthy"} - Verify DB created:
ls -lh db/annotations.db
Extension → Backend Flow#
Create Annotation#
- Load extension in browser
- Navigate to test page:
https://example.com - Select text and create annotation
- Extension should call
POST http://localhost:8080/api/annotations/index - Check server logs: Should see "Indexing annotation: at://..."
- Check server logs: Should see "Successfully indexed annotation"
Verify Database#
sqlite3 server/db/annotations.db "SELECT uri, target_url, exact_text FROM annotations;"
- Verify record exists
- Verify target_url is normalized (no fragment)
- Verify exact_text contains selected text
Query Flow#
Create Multiple Annotations#
- Create 3 annotations on
https://example.com/test - Create 2 annotations on
https://other.com/page
Query by URL#
curl "http://localhost:8080/api/annotations?url=https://example.com/test"
- Returns JSON with
annotationsarray -
countfield shows 3 - Annotations sorted by
createdAtDESC (newest first) - Each annotation has
uri,cid,authorDid,targetUrl,selectors, etc.
Query with Limit#
curl "http://localhost:8080/api/annotations?url=https://example.com/test&limit=2"
- Returns only 2 annotations
- Returns most recent 2
Edge Cases#
Upsert (Duplicate Prevention)#
- Create annotation, note the URI
- Call index endpoint again with same URI but different CID
curl -X POST http://localhost:8080/api/annotations/index \
-H "Content-Type: application/json" \
-d '{"uri":"at://did:plc:test/col/rkey","cid":"new-cid"}'
- Query database: Should have only 1 record (upserted)
- CID should be updated to "new-cid"
Delete Annotation#
# Get URI from query
curl "http://localhost:8080/api/annotations?url=https://example.com/test"
# Delete one (URI as query parameter)
curl -X DELETE "http://localhost:8080/api/annotations?uri=at://did:plc:test/col/rkey"
- Response:
{"success":true,"uri":"..."} - Query again: Count decreased by 1
- Database: Record removed
URL Normalization#
-
Create annotation on
https://example.com/page#section -
Query with
https://example.com/page(no fragment) -
Should return the annotation (URLs normalized)
-
Create annotation on
https://example.com/page/ -
Query with
https://example.com/page(no trailing slash) -
Should return the annotation
Error Handling#
Invalid Requests#
# Missing URI
curl -X POST http://localhost:8080/api/annotations/index \
-H "Content-Type: application/json" \
-d '{"cid":"test"}'
- Response: 400 Bad Request
- Body: "uri is required"
# Missing URL parameter
curl "http://localhost:8080/api/annotations"
- Response: 400 Bad Request
- Body: "url parameter is required"
# Invalid URL
curl "http://localhost:8080/api/annotations?url=not-a-url"
- Response: 500 Internal Server Error (or handle gracefully)
ATProto Fetch Failures#
- Create index request with fake DID
curl -X POST http://localhost:8080/api/annotations/index \
-H "Content-Type: application/json" \
-d '{"uri":"at://did:plc:fake123/col/rkey","cid":"test"}'
- Response: 500 Internal Server Error
- Server logs: "Failed to fetch record: ..."
- Database: No record inserted
Performance#
Bulk Insert Test#
Create test script scripts/bulk-insert.sh:
#!/bin/bash
for i in {1..1000}; do
curl -X POST http://localhost:8080/api/annotations/index \
-H "Content-Type: application/json" \
-d "{\"uri\":\"at://did:plc:test/col/rkey$i\",\"cid\":\"cid$i\"}" \
-s -o /dev/null &
done
wait
- Run script:
bash scripts/bulk-insert.sh - Check database size:
ls -lh db/annotations.db - Query performance:
time curl "http://localhost:8080/api/annotations?url=https://example.com/test"
- Should complete in <100ms
Database Inspection#
# Count total annotations
sqlite3 server/db/annotations.db "SELECT COUNT(*) FROM annotations;"
# Check index usage
sqlite3 server/db/annotations.db "EXPLAIN QUERY PLAN SELECT * FROM annotations WHERE target_url = 'https://example.com';"
# View all records
sqlite3 server/db/annotations.db "SELECT uri, target_url, created_at FROM annotations ORDER BY created_at DESC LIMIT 10;"
Environment Variables#
Custom Database Path#
DB_PATH=/tmp/test-annotations.db go run cmd/server/main.go
- Verify database created at
/tmp/test-annotations.db
Custom Port#
PORT=3000 go run cmd/server/main.go
- Server starts on port 3000
- Health check:
curl http://localhost:3000/health
CORS Testing#
Browser Request#
Open browser console on https://example.com:
fetch('http://localhost:8080/api/annotations?url=https://example.com')
.then(r => r.json())
.then(console.log)
- Request succeeds (CORS enabled)
- Response contains annotations
Clean Up#
# Stop server (Ctrl+C)
# Remove database
rm -rf server/db
# Remove test data
rm /tmp/test-annotations.db