Skip to content

Community social features: public profiles, follows, stars, timeline, avatars - #795

Merged
kody-bot merged 8 commits into
mainfrom
cursor/community-profiles-follows-timeline-1919
Jul 20, 2026
Merged

kody-bot merged 8 commits into
mainfrom
cursor/community-profiles-follows-timeline-1919

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 20, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds the community social layer:

  • Public profiles at /@username — display name, bio, avatar, join date, follower/following counts, and a searchable list of the user's public packages. A saved package is public when its package.json lacks "private": true (projected to saved_packages.is_private; new saves still inject private: true by default). Community-published packages carry a Community badge with a Fork link; public-but-unpublished packages show metadata only (name, kody id, description, tags, updated date) — never README or source, and no forking.
  • Privacy — profiles are public by default and can be set private in account settings. Private profiles 404 (same response as unknown usernames), are excluded from stargazer lists and timelines, can't be followed, and get no OG image.
  • Follows + timeline — one-directional follows (user_follows), and /timeline shows followees' public activity chronologically. Publish/update events are stored in community_activity_events (backfilled from existing listings' published_at); fork and star events are derived at read time, so a fork disappears from timelines the moment the forked copy goes private, and unstarring removes the star entry. Ratings never appear in timelines.
  • Stars / stargazers — GitHub-style favorites on community listings (community_stars), distinct from the existing 1–5 ratings. Star counts on listing cards/detail/OG image, public stargazer lists (public profiles only), and an /account/stars page with unstar.
  • Avatars — PNG/JPEG/WebP uploads (1 MB cap, header-validated dimensions 64–4096px, no SVG) stored content-addressed in the COMMUNITY_ASSETS R2 bucket, served immutable at /profiles/:username/avatar/:cacheKey, shown on profiles, timelines, stargazer lists, and profile OG images.
  • OG images — satori-rendered profile cards at /profiles/:username/og.png (avatar or initial placeholder, bio, follower/package/listing stats) plus star count added to the community listing OG stats row; profile pages emit full OG/Twitter meta tags.
  • MCP capabilities (community domain): community_profile_get, community_profile_update, community_follow, community_unfollow, community_timeline, community_star, community_unstar, community_starred_list; additive star_count, stargazers, owner_username, owner_profile_url, and avatar URL fields on existing outputs (owner_anonymous untouched).
  • Account lifecycle — deletion removes follows (both directions), stars, activity events, and the avatar R2 object; export includes the new tables with other users' stable ids redacted.

Merged with main's username-change package-scope work (#792 era): profile-field saves compose with the username rename flow, and an unchanged username is now a no-op so accounts holding grandfathered/reserved usernames can still edit display name, bio, and visibility. Migrations renumbered to 0068/0069 after main took 0065–0067.

Decision that deserves explicit sign-off

Existing saved_packages rows are migrated with is_private = 1 (safe default). Privacy is recomputed from package.json on every package re-save, and the guarded POST /__maintenance/backfill-package-privacy endpoint recomputes it for all existing packages. Because pre-existing packages never had a private field, running the backfill makes the metadata (name, kody id, description, tags) of most existing packages visible on their owners' public profiles. That matches the agreed rule ("no private: true ⇒ public") but is retroactive — run the backfill deliberately.

Hardening applied after independent review

Export redacts other users' stable ids; public display names never fall back to email local parts; private-profile avatars serve Cache-Control: private, no-store; hidden packages are excluded from public profiles and search_text is not publicly searchable; community_unfollow no longer distinguishes unknown vs private profiles; follow cap aligned with the 2000-followee timeline bound and timeline chunks query concurrently; the privacy backfill no longer bumps updated_at.

Testing

  • npm run validate fully green post-merge (format, lint, typecheck, 990+ unit tests, 18 Playwright E2E including a new community-social spec and profile OG coverage, MCP E2E, primitives check). One local-only e2e hiccup was stale .wrangler/state/e2e from the migration renumbering; fresh state (as in CI) passes.
  • Manual GUI walkthrough on the local dev server (video below): avatar upload with live preview, profile pages, follow, package search, star + stargazers, timeline, starred-packages page.

community_social_features_full_demo.mp4

OG image samples:

Profile OG image with avatar and bio
Profile OG image with initial placeholder
Listing OG image with star count

System recap — adds a new primitive (high risk)

Mode: recap · Base: main @ 9aede048 · Head: 56ecdb7d

Classification: adds — new community-social primitive (profiles, follows, stars, activity timeline); extends community-listings, saved-packages, d1-app-db, community-assets-r2, account-export, and mcp-server outputs; composes app-ui wiring.

Primitives touched

Primitive Group Impact
community-social assistant adds — profiles, follows, stars, activity events (0068, 0069, social-repo/social-service)
community-listings assistant extends — star aggregates, stargazers, activity hooks on publish/unpublish/delete
saved-packages assistant extends — is_private projection from package.json, privacy backfill endpoint
d1-app-db storage extends — users.display_name/bio/profile_visibility/avatar_key, 3 new tables
community-assets-r2 storage extends — user-avatars/<user>/<hash> objects
account-export assistant extends — new tables exported with cross-user id redaction; deletion targets
mcp-server surfaces extends — 8 new community_* capabilities, additive output fields
app-ui surfaces composes — /@username, /timeline, /account/stars, account profile/avatar settings

System map

Profile, timeline, and star traffic flows from new app routes through the community-social service into D1, with avatars in R2 and the same service backing the new MCP capabilities.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).

flowchart LR
	appUi["app-ui<br/>Browser app"]:::touched
	communitySocial["community-social<br/>Profiles, follows, stars, timeline"]:::added
	communityListings["community-listings<br/>Community package listings"]:::extended
	savedPackages["saved-packages<br/>Saved packages"]:::extended
	d1AppDb["d1-app-db<br/>D1 app database"]:::extended
	communityAssetsR2["community-assets-r2<br/>Community R2 assets"]:::extended
	mcpServer["mcp-server<br/>MCP endpoint"]:::extended
	accountExport["account-export<br/>Account data export"]:::extended
	appUi -->|"/@username, /timeline, star/follow .json POSTs"| communitySocial
	mcpServer -->|"community_profile_*, follow, star, timeline"| communitySocial
	communitySocial -->|"user_follows, community_stars, community_activity_events"| d1AppDb
	communitySocial -->|"derived fork/star events, star aggregates"| communityListings
	communitySocial -->|"is_private = 0 package metadata only"| savedPackages
	appUi -->|"avatar upload + /profiles/:username/avatar/:hash"| communityAssetsR2
	accountExport -->|"redacted export + deletion targets"| d1AppDb
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Invariants

  • community-listing-isolation: preserved — profile package lists expose projected metadata only; snapshots/README stay listing-gated.
  • New invariant community-social-privacy added to the map: private profiles/packages never serialize cross-user; public payload mappers rebuild objects field-by-field so stable user ids, emails, and internal package ids never leave the server.
Open in Web Open in Cursor 

@coderabbitai

coderabbitai Bot commented Jul 20, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 145 files, which is 45 over the limit of 100.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d870d4ca-3c55-4d47-b41d-e536812e98b5

📥 Commits

Reviewing files that changed from the base of the PR and between 9aede04 and 7b588d9.

📒 Files selected for processing (145)
  • docs/contributing/architecture/data-storage.md
  • docs/contributing/architecture/primitives.yaml
  • docs/contributing/community-packages.md
  • docs/use/community-packages.md
  • docs/use/community-profiles.md
  • docs/use/index.md
  • docs/use/privacy.md
  • docs/use/search.md
  • e2e/community-social.spec.ts
  • e2e/og-images.spec.ts
  • packages/worker/client/app.tsx
  • packages/worker/client/routes/account-management-components.tsx
  • packages/worker/client/routes/account-stars.tsx
  • packages/worker/client/routes/account.tsx
  • packages/worker/client/routes/community-detail.tsx
  • packages/worker/client/routes/index.tsx
  • packages/worker/client/routes/profile-search.ts
  • packages/worker/client/routes/profile.tsx
  • packages/worker/client/routes/timeline.tsx
  • packages/worker/migrations/0068-community-social.sql
  • packages/worker/migrations/0069-user-avatars.sql
  • packages/worker/src/app/account-data-targets.ts
  • packages/worker/src/app/account-deletion.node.test.ts
  • packages/worker/src/app/account-deletion.ts
  • packages/worker/src/app/account-export.node.test.ts
  • packages/worker/src/app/account-export.ts
  • packages/worker/src/app/account-profile-data.ts
  • packages/worker/src/app/account-stars-data.ts
  • packages/worker/src/app/community-activity-display.ts
  • packages/worker/src/app/community-data.ts
  • packages/worker/src/app/community-detail-content.tsx
  • packages/worker/src/app/community-listings-content.tsx
  • packages/worker/src/app/community-public-types.ts
  • packages/worker/src/app/community-public.ts
  • packages/worker/src/app/frame-registrations.ts
  • packages/worker/src/app/frames/profile.ts
  • packages/worker/src/app/handlers/account-avatar.node.test.ts
  • packages/worker/src/app/handlers/account-avatar.ts
  • packages/worker/src/app/handlers/account-package-invocation-tokens.node.test.ts
  • packages/worker/src/app/handlers/account-profile.node.test.ts
  • packages/worker/src/app/handlers/account-profile.ts
  • packages/worker/src/app/handlers/account-secrets.node.test.ts
  • packages/worker/src/app/handlers/account-stars.ts
  • packages/worker/src/app/handlers/account.ts
  • packages/worker/src/app/handlers/community-detail-og-image.node.test.ts
  • packages/worker/src/app/handlers/community-detail.frame.node.test.ts
  • packages/worker/src/app/handlers/community-detail.tsx
  • packages/worker/src/app/handlers/community-star.node.test.ts
  • packages/worker/src/app/handlers/community-star.ts
  • packages/worker/src/app/handlers/community.frame.node.test.ts
  • packages/worker/src/app/handlers/community.node.test.ts
  • packages/worker/src/app/handlers/package-app.node.test.ts
  • packages/worker/src/app/handlers/profile-avatar.node.test.ts
  • packages/worker/src/app/handlers/profile-avatar.ts
  • packages/worker/src/app/handlers/profile-og-image.node.test.ts
  • packages/worker/src/app/handlers/profile.frame.node.test.ts
  • packages/worker/src/app/handlers/profile.node.test.ts
  • packages/worker/src/app/handlers/profile.tsx
  • packages/worker/src/app/handlers/timeline.node.test.ts
  • packages/worker/src/app/handlers/timeline.tsx
  • packages/worker/src/app/loader-data.ts
  • packages/worker/src/app/profile-content.tsx
  • packages/worker/src/app/profile-data.ts
  • packages/worker/src/app/profile-frame-constants.ts
  • packages/worker/src/app/router.ts
  • packages/worker/src/app/routes.ts
  • packages/worker/src/app/ssr-render.node.test.ts
  • packages/worker/src/app/timeline-data.ts
  • packages/worker/src/app/user-avatar.tsx
  • packages/worker/src/community/avatar.node.test.ts
  • packages/worker/src/community/avatar.ts
  • packages/worker/src/community/community-flow-test-schema.ts
  • packages/worker/src/community/community-flow.workers.test.ts
  • packages/worker/src/community/community-icon.ts
  • packages/worker/src/community/community-scoring.node.test.ts
  • packages/worker/src/community/community-service.node.test.ts
  • packages/worker/src/community/community-social-migration.node.test.ts
  • packages/worker/src/community/og-image.node.test.ts
  • packages/worker/src/community/og-image.ts
  • packages/worker/src/community/og-image.workers.test.ts
  • packages/worker/src/community/profile-og-image.node.test.ts
  • packages/worker/src/community/profile-og-image.ts
  • packages/worker/src/community/profile-og-image.workers.test.ts
  • packages/worker/src/community/repo.ts
  • packages/worker/src/community/service.ts
  • packages/worker/src/community/social-repo.ts
  • packages/worker/src/community/social-service.ts
  • packages/worker/src/community/social-service.workers.test.ts
  • packages/worker/src/community/types.ts
  • packages/worker/src/db.ts
  • packages/worker/src/email/inbound.workers.test.ts
  • packages/worker/src/email/system-email-subscriptions.workers.test.ts
  • packages/worker/src/index.ts
  • packages/worker/src/maintenance-handler.ts
  • packages/worker/src/mcp/capabilities/community/domain.ts
  • packages/worker/src/mcp/capabilities/community/follow.ts
  • packages/worker/src/mcp/capabilities/community/get.ts
  • packages/worker/src/mcp/capabilities/community/profile-get.ts
  • packages/worker/src/mcp/capabilities/community/profile-update.ts
  • packages/worker/src/mcp/capabilities/community/search.ts
  • packages/worker/src/mcp/capabilities/community/shared.ts
  • packages/worker/src/mcp/capabilities/community/social-capabilities.node.test.ts
  • packages/worker/src/mcp/capabilities/community/social-shared.ts
  • packages/worker/src/mcp/capabilities/community/star.ts
  • packages/worker/src/mcp/capabilities/community/starred-list.ts
  • packages/worker/src/mcp/capabilities/community/timeline.ts
  • packages/worker/src/mcp/capabilities/community/unfollow.ts
  • packages/worker/src/mcp/capabilities/community/unstar.ts
  • packages/worker/src/mcp/capabilities/openapi-provider/operation-request.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/create-stub-package.ts
  • packages/worker/src/mcp/capabilities/packages/get-package.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/list-package-subscriptions.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/package-update.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/save-package-entitlements.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/save-package-private-visibility.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/save-package.ts
  • packages/worker/src/mcp/capabilities/repo/repo-list-sessions.node.test.ts
  • packages/worker/src/mcp/capabilities/repo/repo-open-session.node.test.ts
  • packages/worker/src/mcp/capabilities/repo/repo-workflow.node.test.ts
  • packages/worker/src/mcp/capabilities/services/service-start.node.test.ts
  • packages/worker/src/mcp/capabilities/services/services-domain.node.test.ts
  • packages/worker/src/mcp/fetch-gateway.node.test.ts
  • packages/worker/src/mcp/tools/package-search-identity.node.test.ts
  • packages/worker/src/mcp/tools/search-format.node.test.ts
  • packages/worker/src/mcp/tools/search-handler.node.test.ts
  • packages/worker/src/mcp/tools/search-hidden-packages.node.test.ts
  • packages/worker/src/mcp/tools/search.node.test.ts
  • packages/worker/src/mcp/tools/search.ts
  • packages/worker/src/package-invocations/service.node.test.ts
  • packages/worker/src/package-registry/manifest.ts
  • packages/worker/src/package-registry/package-reindex.node.test.ts
  • packages/worker/src/package-registry/repo-search.workers.test.ts
  • packages/worker/src/package-registry/repo.ts
  • packages/worker/src/package-registry/saved-packages-hidden-migration.node.test.ts
  • packages/worker/src/package-registry/service.node.test.ts
  • packages/worker/src/package-registry/service.ts
  • packages/worker/src/package-registry/types.ts
  • packages/worker/src/package-retrievers/manifest-cache.node.test.ts
  • packages/worker/src/package-runtime/module-graph.node.test.ts
  • packages/worker/src/package-runtime/module-graph.workers.test.ts
  • packages/worker/src/package-runtime/published-bundle-artifacts.node.test.ts
  • packages/worker/src/platform-feedback/package-subscriptions.node.test.ts
  • packages/worker/src/platform-feedback/platform-feedback-subscriptions.workers.test.ts
  • packages/worker/src/repo/published-bundle-artifacts-repo.workers.test.ts
  • packages/worker/tsconfig-client.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Review on demand using usage pricing
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/community-profiles-follows-timeline-1919

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kody-bot
kody-bot marked this pull request as ready for review July 20, 2026 02:40
…iles-follows-timeline-1919

# Conflicts:
#	packages/worker/client/routes/account.tsx
#	packages/worker/src/app/handlers/account-profile.node.test.ts
#	packages/worker/src/app/handlers/account-profile.ts
@github-actions

github-actions Bot commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-795.kody-a99.workers.dev

Worker: kody-pr-795
D1: kody-pr-795-db
KV: kody-pr-795-oauth-kv

Mocks:

Comment thread packages/worker/src/community/social-repo.ts
Comment thread packages/worker/src/community/social-repo.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7b588d9. Configure here.


const items = chunkResults.flat()
items.sort(compareActivityItems)
return items.slice(0, input.limit)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timeline merge drops global events

Medium Severity

listCommunityActivityForActors splits followees into SQL chunks and applies the final timeline limit separately on each chunk’s stored, fork, and star queries before merging. Recent activity from one chunk can be omitted from the merged feed even when it should rank above older items returned from other chunks, so /timeline and community_timeline can show an incomplete or wrongly ordered feed for users who follow many accounts.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7b588d9. Configure here.

})
} catch (error) {
if (error instanceof CommunityActionError) {
return jsonResponse({ ok: false, error: error.message }, 400)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Profile save not atomic with rename

Medium Severity

A single profile POST can rename the username and then update community profile fields. Username scope work runs first and commits; if updateCommunityProfile fails afterward, the handler returns an error but leaves the new username in place without applying the requested display name, bio, or visibility changes.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7b588d9. Configure here.

@kody-bot
kody-bot merged commit a270fcc into main Jul 20, 2026
5 checks passed
@kody-bot
kody-bot deleted the cursor/community-profiles-follows-timeline-1919 branch July 20, 2026 03:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants