See the best posts from any Bluesky account
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add is_featured flag to tracked profiles for curated landing page examples

Landing page now shows 3 random featured profiles instead of hardcoded
handles, with fallback to defaults when no profiles are marked. Re-running
seed:top-accounts sets is_featured=true on already-tracked accounts. Also
fixes pre-existing Test 10 timeout by faking the queue during dispatch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+91 -10
+3 -1
app/lib/bluecrawler/seeder.ts
··· 28 28 for (let i = 0; i < accounts.length; i++) { 29 29 const account = accounts[i] 30 30 31 - // Skip if user already exists 31 + // Mark as featured if user already exists 32 32 const existing = await TrackedProfile.find(account.did) 33 33 if (existing) { 34 + existing.isFeatured = true 35 + await existing.save() 34 36 skipped++ 35 37 onProgress?.(i + 1, accounts.length) 36 38 continue
+3
app/models/tracked_profile.ts
··· 28 28 29 29 @column() 30 30 declare deletedAt: number | null 31 + 32 + @column() 33 + declare isFeatured: boolean 31 34 }
+48 -9
tests/functional/profile_controller.spec.ts
··· 11 11 import { fileURLToPath } from 'node:url' 12 12 import { join } from 'node:path' 13 13 import testUtils from '@adonisjs/core/services/test_utils' 14 + import queue from '@adonisjs/queue/services/main' 14 15 import { ClickHouseStore } from '#lib/clickhouse/index' 15 16 import { AtprotoClient } from '#lib/atproto/index' 16 17 import { HandleResolver } from '#services/handle_resolver' ··· 92 93 assert.include(response.text(), 'favs.blue') 93 94 }) 94 95 96 + // Test 1b: Landing page shows random featured profiles 97 + test('GET / shows featured tracked profiles as examples', async ({ client, assert }) => { 98 + await TrackedProfile.createMany([ 99 + { did: 'did:plc:aaa', handle: 'featured1.bsky.social', isFeatured: true, firstSeenAt: Date.now() }, 100 + { did: 'did:plc:bbb', handle: 'featured2.bsky.social', isFeatured: true, firstSeenAt: Date.now() }, 101 + { did: 'did:plc:ccc', handle: 'featured3.bsky.social', isFeatured: true, firstSeenAt: Date.now() }, 102 + { did: 'did:plc:ddd', handle: 'featured4.bsky.social', isFeatured: true, firstSeenAt: Date.now() }, 103 + { did: 'did:plc:eee', handle: 'notfeatured.bsky.social', isFeatured: false, firstSeenAt: Date.now() }, 104 + ]) 105 + 106 + const response = await client.get('/') 107 + response.assertStatus(200) 108 + const body = response.text() 109 + 110 + // Non-featured profile should not appear 111 + assert.notInclude(body, 'notfeatured.bsky.social') 112 + 113 + // Exactly 3 of the 4 featured profiles should appear 114 + const featured = ['featured1.bsky.social', 'featured2.bsky.social', 'featured3.bsky.social', 'featured4.bsky.social'] 115 + const found = featured.filter((h) => body.includes(h)) 116 + assert.equal(found.length, 3) 117 + }) 118 + 119 + // Test 1c: Landing page falls back to hardcoded handles when no featured profiles exist 120 + test('GET / falls back to hardcoded examples when no featured profiles exist', async ({ 121 + client, 122 + assert, 123 + }) => { 124 + const response = await client.get('/') 125 + response.assertStatus(200) 126 + assert.include(response.text(), 'dril.bsky.social') 127 + }) 128 + 95 129 // Test 2: GET /about returns 200 96 130 test('GET /about returns 200', async ({ client }) => { 97 131 const response = await client.get('/about') ··· 153 187 assert, 154 188 swap, 155 189 }) => { 190 + queue.fake() 156 191 swap(HandleResolver, { 157 192 normalize: (h: string) => h.toLowerCase(), 158 193 async resolveToDid() { ··· 167 202 return { postsCount: 42 } 168 203 }, 169 204 } as unknown as AtprotoClient) 170 - const response = await client.get('/profile/dril.bsky.social/likes?days=30') 171 - response.assertStatus(200) 172 - const html = response.text() 173 - assert.include(html, 'meta http-equiv="refresh"') 174 - assert.include(html, 'Indexing') 175 - // Task 4: live SSE-driven progress bar with Alpine component 176 - assert.include(html, 'role="progressbar"') 177 - assert.include(html, 'x-data="backfillProgress(') 178 - assert.include(html, 'aria-valuemax="42"') 205 + try { 206 + const response = await client.get('/profile/dril.bsky.social/likes?days=30') 207 + response.assertStatus(200) 208 + const html = response.text() 209 + assert.include(html, 'meta http-equiv="refresh"') 210 + assert.include(html, 'Indexing') 211 + // Task 4: live SSE-driven progress bar with Alpine component 212 + assert.include(html, 'role="progressbar"') 213 + assert.include(html, 'x-data="backfillProgress(') 214 + assert.include(html, 'aria-valuemax="42"') 215 + } finally { 216 + queue.restore() 217 + } 179 218 }) 180 219 181 220 // Test 17: GET /profile/:handle preserves ?days= when redirecting to canonical /likes
+22
tests/unit/seed_top_accounts.spec.ts
··· 97 97 assert.lengthOf(dispatched, 0) 98 98 }) 99 99 100 + test('sets isFeatured on already-tracked accounts', async ({ assert }) => { 101 + const accounts = makeAccounts(2) 102 + 103 + // Pre-create both users (isFeatured defaults to false) 104 + for (const account of accounts) { 105 + await TrackedProfile.create({ 106 + did: account.did, 107 + handle: account.handle, 108 + firstSeenAt: Date.now(), 109 + }) 110 + } 111 + 112 + const result = await seedTopAccounts(accounts, async () => {}) 113 + 114 + assert.equal(result.skipped, 2) 115 + 116 + for (const account of accounts) { 117 + const user = await TrackedProfile.find(account.did) 118 + assert.ok(user!.isFeatured, `${account.handle} should be featured after re-seed`) 119 + } 120 + }) 121 + 100 122 test('reports progress via callback', async ({ assert }) => { 101 123 const accounts = makeAccounts(5) 102 124 const progressCalls: Array<{ current: number; total: number }> = []