···16{"id":"01KGDXVR86CB2H44DJHKN4Z9M0","title":"Implement comments for social interactions","description":"Add a comment lexicon and implement comment functionality across the app.\n\n## Lexicon: social.arabica.alpha.comment\n\nThe comment record should:\n- Use `com.atproto.repo.strongRef` for the subject (URI + CID for immutability)\n- Support commenting on any arabica.social lexicon type (beans, roasters, grinders, brewers, brews, and other comments)\n- Include text field (max 1000 chars / 300 graphemes as per AT Protocol conventions)\n- Include createdAt timestamp\n- Use TID as record key\n- NOTE: This cell implements flat comments only. Threaded/nested comments are handled in a separate cell.\n\n## Backend Implementation\n\n1. Create lexicon file: `lexicons/social.arabica.alpha.comment.json`\n2. Add NSID constant in `internal/atproto/nsid.go`\n3. Add Comment model in `internal/models/models.go`\n4. Add record conversion functions in `internal/atproto/records.go`\n5. Add Store interface methods: CreateComment, DeleteComment, GetCommentsForSubject, GetUserComments\n6. Implement in AtprotoStore\n7. Update firehose indexing to track comments\n\n## Frontend Implementation\n\n1. Add comment section component below brew detail view\n2. Add comment form (authenticated users only)\n3. Display comment count on records in feed\n4. Update comment counts in response to firehose events\n5. Show commenter profile info (avatar, handle)\n\n## Acceptance Criteria\n\n- Users can comment on any arabica.social record\n- Comments are stored in the user's PDS (actor-owned data)\n- Comment counts display on records in the feed\n- Comments visible on record detail views\n- Real-time comment count updates via firehose","status":"open","priority":"normal","labels":["backend","frontend","atproto"],"created_at":"2026-02-02T01:00:51.846427126Z","updated_at":"2026-02-02T01:00:51.846427126Z"}
17{"id":"01KGDXW31PHFMBE3WTV83HPET1","title":"Implement comment threading","description":"Add support for threaded/nested comments, building on the flat comment system.\n\n## Lexicon Changes\n\nUpdate `social.arabica.alpha.comment` to add optional threading fields:\n- `parent`: Optional strongRef to parent comment (for replies)\n- `root`: Optional strongRef to root subject (maintains context when replying to comments)\n\nAlternatively, consider a separate reply field or keeping comments flat with UI-level threading.\n\n## Backend Implementation\n\n1. Update comment model to include parent/root references\n2. Add methods to fetch comment threads: GetCommentThread, GetReplies\n3. Update firehose indexing to track parent-child relationships\n4. Add depth limits for threading (prevent infinite nesting)\n\n## Frontend Implementation\n\n1. Design threaded comment UI (indentation, collapse/expand)\n2. Add 'reply' button on comments\n3. Show reply context when replying\n4. Consider max nesting depth for display (e.g., 3-4 levels)\n5. Mobile-friendly thread navigation\n\n## Design Considerations\n\n- How deep should threading go? (Recommend max 3-4 levels visible, then flatten)\n- How to handle deleted parent comments?\n- Should users be notified when someone replies to their comment?\n- Performance: lazy-load deep threads vs eager-load\n\n## Acceptance Criteria\n\n- Users can reply directly to comments\n- Thread structure is visually clear\n- Threads can be collapsed/expanded\n- Works well on mobile devices\n- Parent context shown when replying","status":"blocked","priority":"low","blocked_by":["01KGDXVR86CB2H44DJHKN4Z9M0"],"labels":["frontend","atproto"],"created_at":"2026-02-02T01:01:02.902692829Z","updated_at":"2026-02-02T01:01:06.361891137Z"}
18{"id":"01KJ36P2BWM4HSZV6GNX0BJB1F","title":"Implement lightweight For You feed algorithm","description":"Add a 'For You' algorithmic feed tab alongside the existing chronological feed. This should be a lightweight scoring system that ranks posts based on:\n\n**Scoring Factors:**\n1. **Engagement score**: likes (weight 3x) + comments (weight 2x) on the post\n2. **Time decay**: Score multiplied by a decay factor based on post age. Use exponential decay with a half-life of ~24 hours so recent engaged content surfaces while popular older content still has a chance.\n3. **Type diversity**: After scoring, apply a diversity pass to avoid showing too many of the same record type in a row. If 3+ consecutive items are the same type, interleave with the next different-type item.\n4. **Social proximity** (future): Boost posts from users the viewer has interacted with (liked their content, commented on their posts). This requires building a per-user interaction graph from the like/comment indexes.\n\n**Implementation approach:**\n- Add a new `FeedSortForYou` sort option alongside recent/popular\n- Add a `scoreForYouItem(item *FeedItem, viewerDID string) float64` function in the firehose index\n- Fetch ~100 recent items, score them, apply diversity, return top N\n- Add a 'For You' tab in the feed filter bar UI (only for authenticated users)\n- Cache scored results per-viewer with short TTL (1-2 min) to avoid re-scoring on pagination\n\n**Key files:**\n- `internal/firehose/index.go` - Add scoring logic and ForYou query\n- `internal/feed/service.go` - Add FeedSortForYou constant\n- `internal/firehose/adapter.go` - Pass through ForYou sort\n- `internal/handlers/feed.go` - Handle sort=foryou param\n- `internal/web/pages/feed.templ` - Add For You tab\n\n**Dependencies:**\n- Relies on existing BucketByTime, BucketLikeCounts, BucketCommentCounts, BucketLikesByActor indexes\n- Social proximity scoring depends on being able to query BucketLikesByActor efficiently","status":"open","priority":"normal","created_at":"2026-02-22T17:34:47.67684351Z","updated_at":"2026-02-22T17:34:47.67684351Z"}
0
···16{"id":"01KGDXVR86CB2H44DJHKN4Z9M0","title":"Implement comments for social interactions","description":"Add a comment lexicon and implement comment functionality across the app.\n\n## Lexicon: social.arabica.alpha.comment\n\nThe comment record should:\n- Use `com.atproto.repo.strongRef` for the subject (URI + CID for immutability)\n- Support commenting on any arabica.social lexicon type (beans, roasters, grinders, brewers, brews, and other comments)\n- Include text field (max 1000 chars / 300 graphemes as per AT Protocol conventions)\n- Include createdAt timestamp\n- Use TID as record key\n- NOTE: This cell implements flat comments only. Threaded/nested comments are handled in a separate cell.\n\n## Backend Implementation\n\n1. Create lexicon file: `lexicons/social.arabica.alpha.comment.json`\n2. Add NSID constant in `internal/atproto/nsid.go`\n3. Add Comment model in `internal/models/models.go`\n4. Add record conversion functions in `internal/atproto/records.go`\n5. Add Store interface methods: CreateComment, DeleteComment, GetCommentsForSubject, GetUserComments\n6. Implement in AtprotoStore\n7. Update firehose indexing to track comments\n\n## Frontend Implementation\n\n1. Add comment section component below brew detail view\n2. Add comment form (authenticated users only)\n3. Display comment count on records in feed\n4. Update comment counts in response to firehose events\n5. Show commenter profile info (avatar, handle)\n\n## Acceptance Criteria\n\n- Users can comment on any arabica.social record\n- Comments are stored in the user's PDS (actor-owned data)\n- Comment counts display on records in the feed\n- Comments visible on record detail views\n- Real-time comment count updates via firehose","status":"open","priority":"normal","labels":["backend","frontend","atproto"],"created_at":"2026-02-02T01:00:51.846427126Z","updated_at":"2026-02-02T01:00:51.846427126Z"}
17{"id":"01KGDXW31PHFMBE3WTV83HPET1","title":"Implement comment threading","description":"Add support for threaded/nested comments, building on the flat comment system.\n\n## Lexicon Changes\n\nUpdate `social.arabica.alpha.comment` to add optional threading fields:\n- `parent`: Optional strongRef to parent comment (for replies)\n- `root`: Optional strongRef to root subject (maintains context when replying to comments)\n\nAlternatively, consider a separate reply field or keeping comments flat with UI-level threading.\n\n## Backend Implementation\n\n1. Update comment model to include parent/root references\n2. Add methods to fetch comment threads: GetCommentThread, GetReplies\n3. Update firehose indexing to track parent-child relationships\n4. Add depth limits for threading (prevent infinite nesting)\n\n## Frontend Implementation\n\n1. Design threaded comment UI (indentation, collapse/expand)\n2. Add 'reply' button on comments\n3. Show reply context when replying\n4. Consider max nesting depth for display (e.g., 3-4 levels)\n5. Mobile-friendly thread navigation\n\n## Design Considerations\n\n- How deep should threading go? (Recommend max 3-4 levels visible, then flatten)\n- How to handle deleted parent comments?\n- Should users be notified when someone replies to their comment?\n- Performance: lazy-load deep threads vs eager-load\n\n## Acceptance Criteria\n\n- Users can reply directly to comments\n- Thread structure is visually clear\n- Threads can be collapsed/expanded\n- Works well on mobile devices\n- Parent context shown when replying","status":"blocked","priority":"low","blocked_by":["01KGDXVR86CB2H44DJHKN4Z9M0"],"labels":["frontend","atproto"],"created_at":"2026-02-02T01:01:02.902692829Z","updated_at":"2026-02-02T01:01:06.361891137Z"}
18{"id":"01KJ36P2BWM4HSZV6GNX0BJB1F","title":"Implement lightweight For You feed algorithm","description":"Add a 'For You' algorithmic feed tab alongside the existing chronological feed. This should be a lightweight scoring system that ranks posts based on:\n\n**Scoring Factors:**\n1. **Engagement score**: likes (weight 3x) + comments (weight 2x) on the post\n2. **Time decay**: Score multiplied by a decay factor based on post age. Use exponential decay with a half-life of ~24 hours so recent engaged content surfaces while popular older content still has a chance.\n3. **Type diversity**: After scoring, apply a diversity pass to avoid showing too many of the same record type in a row. If 3+ consecutive items are the same type, interleave with the next different-type item.\n4. **Social proximity** (future): Boost posts from users the viewer has interacted with (liked their content, commented on their posts). This requires building a per-user interaction graph from the like/comment indexes.\n\n**Implementation approach:**\n- Add a new `FeedSortForYou` sort option alongside recent/popular\n- Add a `scoreForYouItem(item *FeedItem, viewerDID string) float64` function in the firehose index\n- Fetch ~100 recent items, score them, apply diversity, return top N\n- Add a 'For You' tab in the feed filter bar UI (only for authenticated users)\n- Cache scored results per-viewer with short TTL (1-2 min) to avoid re-scoring on pagination\n\n**Key files:**\n- `internal/firehose/index.go` - Add scoring logic and ForYou query\n- `internal/feed/service.go` - Add FeedSortForYou constant\n- `internal/firehose/adapter.go` - Pass through ForYou sort\n- `internal/handlers/feed.go` - Handle sort=foryou param\n- `internal/web/pages/feed.templ` - Add For You tab\n\n**Dependencies:**\n- Relies on existing BucketByTime, BucketLikeCounts, BucketCommentCounts, BucketLikesByActor indexes\n- Social proximity scoring depends on being able to query BucketLikesByActor efficiently","status":"open","priority":"normal","created_at":"2026-02-22T17:34:47.67684351Z","updated_at":"2026-02-22T17:34:47.67684351Z"}
19+{"id":"01KJ37P3RD4X4P7B8F5EWE6NWB","title":"Add Prometheus metrics endpoint","description":"Add prometheus/client_golang instrumentation to Arabica with a /metrics endpoint. Minimal but useful instrumentation points:\n\n## Metrics to implement\n\n### HTTP middleware (internal/middleware/)\n- `arabica_http_requests_total` counter: labels: method, path, status\n- `arabica_http_request_duration_seconds` histogram: labels: method, path\n\n### Firehose consumer (internal/firehose/)\n- `arabica_firehose_events_total` counter: labels: collection, operation\n- `arabica_firehose_connection_state` gauge: 1=connected, 0=disconnected\n- `arabica_firehose_errors_total` counter\n\n### PDS client (internal/atproto/)\n- `arabica_pds_requests_total` counter: labels: method, collection\n- `arabica_pds_request_duration_seconds` histogram: labels: method\n- `arabica_pds_errors_total` counter: labels: method\n\n### Feed service (internal/feed/)\n- `arabica_feed_cache_hits_total` counter\n- `arabica_feed_cache_misses_total` counter\n\n## Implementation notes\n- Add `github.com/prometheus/client_golang` dependency\n- Expose /metrics endpoint in routing.go (no auth required)\n- Keep cardinality low: normalize path labels (e.g. /brews/{id} -\u003e /brews/:id)\n- Create a grafana/arabica-prometheus.json dashboard alongside the existing log-based one\n- Existing log-based dashboard is at grafana/arabica-logs.json for reference","status":"completed","priority":"normal","assignee":"patrick","labels":["backend","observability"],"created_at":"2026-02-22T17:52:17.677417112Z","updated_at":"2026-02-22T17:57:56.326244513Z","completed_at":"2026-02-22T17:57:56.315753758Z"}
···1+# Grafana Dashboards
2+3+Importable Grafana dashboard definitions for monitoring Arabica.
4+5+## Dashboards
6+7+### `arabica-logs.json` - Log-Based Metrics
8+9+Queries structured JSON logs via **Loki**. No code changes needed - works with existing zerolog output.
10+11+**Prerequisite:** Ship Arabica logs to Loki (e.g., via Promtail, Alloy, or Docker log driver). Logs must be in JSON format (`LOG_FORMAT=json`).
12+13+**Log selector:** The dashboard uses a template variable (`$log_selector`) with three presets:
14+15+- `unit="arabica.service"` (default) - NixOS/systemd journal via Promtail
16+- `syslog_identifier="arabica"` - journald syslog identifier
17+- `app="arabica"` - Docker log driver or custom labels
18+19+Select the matching option from the dropdown at the top of the dashboard, or type a custom value.
20+21+**Sections:**
22+23+- **Overview** - stat panels for total requests, errors, logins, reports, join requests
24+- **HTTP Traffic** - requests by status/method, top paths, response latency
25+- **Firehose** - events by collection/operation, errors, backfill activity
26+- **Authentication & Users** - login success/failure, join requests, invites
27+- **Moderation** - reports, hide/unhide/block actions, permission denials
28+- **PDS & ATProto** - PDS request volume/latency/errors by method and collection
29+- **Errors & Warnings** - error/warn timeline + recent error log viewer
30+31+### `arabica-prometheus.json` - Prometheus Metrics
32+33+Queries instrumented Prometheus counters, histograms, and gauges exposed at `/metrics`.
34+35+**Prerequisite:** Arabica exposes a `/metrics` endpoint (Prometheus format). Configure Prometheus to scrape it.
36+37+**Sections:**
38+39+- **Overview** - request rate, error rate, p95 latency, firehose connection, events/s, cache hit rate
40+- **HTTP Traffic** - request rate by status/path, latency percentiles (p50/p95/p99), latency by path
41+- **Firehose** - events by collection/operation, error rate, connection state
42+- **PDS / ATProto** - PDS request rate by method/collection, latency by method, error rate
43+- **Feed Cache** - cache hits vs misses, hit rate over time
44+45+### Importing
46+47+1. In Grafana, go to **Dashboards > Import**
48+2. Upload the JSON file or paste its contents
49+3. Select your data source (Loki or Prometheus) when prompted
50+4. For the Loki dashboard, select the correct log selector from the dropdown (defaults to `unit="arabica.service"` for NixOS systemd)