blonk is a radar for your web, where you follow vibes for cool blips on the radar

remove stupid crypto references

+12 -10
README.md
··· 36 36 37 37 - `com.blonk.vibe` - Community topic feeds 38 38 - `com.blonk.blip` - Content submissions 39 - - `com.blonk.groove` - Community engagement 39 + - `com.blonk.groove` - Community engagement on specific blips 40 40 - `com.blonk.tag` - Universal content labels 41 41 - `com.blonk.blipTag` - Content categorization associations 42 42 ··· 93 93 Post `#vibe-topic_name` to create new community vibes: 94 94 95 95 ``` 96 - Check out this cool #vibe-blockchain project! #defi #web3 96 + Check out this cool #vibe-art project! #design #creative 97 97 ``` 98 98 99 - Once enough community members use `#vibe-blockchain`, it becomes an official vibe. 99 + Once enough community members use `#vibe-art`, it becomes an official vibe. 100 100 101 101 ### Submitting Blips 102 102 103 103 Submit content to vibes with relevant tags: 104 104 105 105 ``` 106 - Title: "New DeFi Protocol Launch" 107 - Body: "Exciting developments in yield farming..." 108 - Vibe: blockchain_vibe 109 - Tags: #defi #yield #ethereum 106 + Title: "Amazing New Design Framework" 107 + Body: "This changes everything for designers..." 108 + Vibe: design_vibe 109 + Tags: #design #tools #creative 110 110 ``` 111 111 112 112 ### Community Engagement 113 113 114 - - **👍 looks_good** - Positive community feedback 115 - - **💩 shit_rips** - Critical community feedback 114 + Groove on blips to provide community feedback: 116 115 117 - Grooves drive content visibility and trending algorithms. 116 + - **👍 looks_good** - Positive endorsement of the blip 117 + - **shit_rips** - Critical feedback on the blip 118 + 119 + Each groove is linked to a specific blip and drives content visibility on the radar. 118 120 119 121 ### Discovery 120 122
+54 -1
lib/elixir_blonk/atproto.ex
··· 36 36 - `com.blonk.blip` - Content submissions to vibes 37 37 - `com.blonk.tag` - Universal community labels 38 38 - `com.blonk.blipTag` - Content categorization associations 39 + - `com.blonk.groove` - Community engagement records (looks_good/shit_rips) 39 40 - `com.blonk.vibe` - Topic-based community feeds (future) 40 - - `com.blonk.groove` - Community engagement records (future) 41 41 42 42 ## Error Handling 43 43 ··· 55 55 # Create Blonk records 56 56 {:ok, %{uri: uri, cid: cid}} = ATProto.create_blip(client, blip) 57 57 {:ok, %{uri: uri, cid: cid}} = ATProto.create_tag(client, tag) 58 + {:ok, %{uri: uri, cid: cid}} = ATProto.create_groove(client, groove) 58 59 59 60 # Analyze engagement for hot posts 60 61 {:ok, %{reply_count: count}} = ATProto.get_post_engagement(client, post_uri) ··· 254 255 |> compact_record() 255 256 256 257 create_record(client, @blip_tag_nsid, record) 258 + end 259 + 260 + @doc """ 261 + Create a groove (community engagement) record in ATProto. 262 + 263 + Grooves are Blonk's community feedback mechanism, enabling users to express 264 + their reaction to blips through binary engagement (looks_good/shit_rips). 265 + Each groove is tightly linked to a specific blip. 266 + 267 + ## Blip-Groove Relationship 268 + 269 + **Every groove references the blip it's responding to:** 270 + - Groove record includes blip URI/CID for cross-platform reference 271 + - Database foreign key ensures data integrity 272 + - Enables discovery of all grooves for a specific blip 273 + - Powers community-driven content curation algorithms 274 + 275 + ## ATProto Schema (`com.blonk.groove`) 276 + 277 + - `blip` - Reference to the grooved blip (uri/cid) 278 + - `grooveType` - Either "looks_good" or "shit_rips" 279 + - `author` - DID of user creating the groove 280 + - `createdAt` - When this groove was created 281 + 282 + ## Community Impact 283 + 284 + Grooves create the engagement signals that drive Blonk's discovery: 285 + - High groove counts surface popular content on radar 286 + - Community consensus emerges through groove patterns 287 + - Cross-vibe content discovery powered by groove activity 288 + 289 + ## Examples 290 + 291 + # User grooves positively on a blip 292 + {:ok, %{uri: uri, cid: cid}} = ATProto.create_groove(client, groove) 293 + # Results in: at://did:plc:user/com.blonk.groove/rkey 294 + # Links to: at://did:plc:author/com.blonk.blip/tech-post 295 + """ 296 + def create_groove(%__MODULE__{} = client, groove) do 297 + # Get the blip record that this groove is for 298 + blip = ElixirBlonk.Blips.get_blip!(groove.blip_id) 299 + 300 + record = %{ 301 + "$type" => @groove_nsid, 302 + blip: %{uri: blip.uri, cid: blip.cid}, 303 + grooveType: groove.groove_type, 304 + author: groove.author_did, 305 + createdAt: DateTime.to_iso8601(DateTime.utc_now()) 306 + } 307 + |> compact_record() 308 + 309 + create_record(client, @groove_nsid, record) 257 310 end 258 311 259 312 defp compact_record(record) do
+4 -4
lib/elixir_blonk/blip_tags.ex
··· 40 40 ## Examples 41 41 42 42 # Tag a new blip submission 43 - BlipTags.associate_tags_with_blip(blip_id, ["defi", "ethereum"], user_did) 43 + BlipTags.associate_tags_with_blip(blip_id, ["art", "design"], user_did) 44 44 45 - # Find trending crypto content across all vibes 46 - crypto_tag = Tags.get_tag_by_name("crypto") 47 - trending_crypto = BlipTags.get_blips_for_tag(crypto_tag.id) 45 + # Find trending art content across all vibes 46 + art_tag = Tags.get_tag_by_name("art") 47 + trending_art = BlipTags.get_blips_for_tag(art_tag.id) 48 48 49 49 # Clean up tags when content is removed 50 50 BlipTags.remove_all_tags_from_blip(blip_id)
+8 -8
lib/elixir_blonk/blips.ex
··· 59 59 60 60 ## Examples 61 61 62 - # Create a blip for the crypto vibe 62 + # Create a blip for a vibe 63 63 {:ok, blip} = Blips.create_blip(%{ 64 - title: "New DeFi Protocol Launch", 65 - body: "Exciting developments in yield farming...", 66 - url: "https://protocol.xyz", 67 - vibe_uri: crypto_vibe.uri, 68 - tags: ["defi", "yield", "ethereum"], 64 + title: "Amazing New Framework Released", 65 + body: "This changes everything for developers...", 66 + url: "https://example.com/framework", 67 + vibe_uri: tech_vibe.uri, 68 + tags: ["framework", "productivity", "tools"], 69 69 author_did: "did:plc:user123" 70 70 }) 71 71 72 72 # Find blips by tag across all vibes 73 - defi_blips = Blips.list_blips_by_tag("defi") 73 + framework_blips = Blips.list_blips_by_tag("framework") 74 74 75 75 # Search blips by content 76 - search_results = Blips.search_blips("protocol") 76 + search_results = Blips.search_blips("framework") 77 77 """ 78 78 79 79 import Ecto.Query, warn: false
+1 -1
lib/elixir_blonk/firehose/consumer.ex
··· 68 68 ## Examples 69 69 70 70 # Vibe mention detection 71 - "I love this new #vibe-solana ecosystem!" 71 + "I love this new #vibe-art community!" 72 72 → Records vibe mention for potential community creation 73 73 74 74 # Hot post sampling
+38 -12
lib/elixir_blonk/grooves.ex
··· 11 11 12 12 **Grooves are binary community feedback on blips:** 13 13 - **looks_good** (👍) - Positive community endorsement 14 - - **shit_rips** (💩) - Critical community feedback 14 + - **shit_rips** - Critical community feedback 15 15 - Each user can groove once per blip with either reaction 16 16 - Groove counts drive content visibility and trending algorithms 17 17 - Community-driven curation without complex scoring systems ··· 87 87 """ 88 88 89 89 import Ecto.Query, warn: false 90 + require Logger 90 91 alias ElixirBlonk.Repo 91 92 92 93 alias ElixirBlonk.Grooves.Groove ··· 106 107 attrs 107 108 end 108 109 109 - %Groove{} 110 - |> Groove.changeset(attrs) 111 - |> Repo.insert() 112 - |> case do 113 - {:ok, groove} -> 114 - # Update groove counts on the blip 115 - if groove.blip_id do 116 - Blips.update_groove_counts(groove.blip_id) 117 - end 118 - {:ok, groove} 119 - error -> error 110 + # First create in local database 111 + with {:ok, groove} <- %Groove{} 112 + |> Groove.changeset(attrs) 113 + |> Repo.insert() do 114 + 115 + # Update groove counts on the blip 116 + if groove.blip_id do 117 + Blips.update_groove_counts(groove.blip_id) 118 + end 119 + 120 + # Then try to create in ATProto if enabled 121 + if Application.get_env(:elixir_blonk, :atproto_enabled, true) do 122 + Task.Supervisor.start_child(ElixirBlonk.TaskSupervisor, fn -> 123 + create_groove_in_atproto(groove) 124 + end) 125 + end 126 + 127 + {:ok, groove} 120 128 end 121 129 end 122 130 ··· 224 232 |> where([g], g.author_did == ^author_did and g.subject_uri == ^subject_uri) 225 233 |> select([g], g.groove_type) 226 234 |> Repo.one() 235 + end 236 + 237 + # Private functions 238 + 239 + defp create_groove_in_atproto(groove) do 240 + with {:ok, client} <- ElixirBlonk.ATProto.SimpleSession.get_client(), 241 + {:ok, %{uri: uri, cid: cid}} <- ElixirBlonk.ATProto.create_groove(client, groove) do 242 + 243 + # Update local record with ATProto URI and CID 244 + groove 245 + |> Groove.changeset(%{uri: uri, cid: cid}) 246 + |> Repo.update() 247 + 248 + Logger.info("Created groove in ATProto: #{uri}") 249 + else 250 + {:error, reason} -> 251 + Logger.error("Failed to create groove in ATProto: #{inspect(reason)}") 252 + end 227 253 end 228 254 end
+49
lib/elixir_blonk/grooves/groove.ex
··· 1 1 defmodule ElixirBlonk.Grooves.Groove do 2 + @moduledoc """ 3 + Represents community engagement on blips in the Blonk ecosystem. 4 + 5 + Grooves are the fundamental feedback mechanism that drives content curation 6 + and community engagement. Each groove represents a user's reaction to a 7 + specific blip, creating the social signal that powers Blonk's trending 8 + algorithms and community-driven content discovery. 9 + 10 + ## Blip-Groove Relationship 11 + 12 + **Every groove is tightly coupled to a specific blip:** 13 + - `blip_id` - Database foreign key to the blip being grooved 14 + - `subject_uri` - ATProto URI of the blip for cross-platform reference 15 + - `belongs_to :blip` - Ecto association for database queries 16 + - Cascade deletion when blip is removed 17 + 18 + ## ATProto Integration 19 + 20 + **Grooves become `com.blonk.groove` ATProto records:** 21 + - `uri` - ATProto record URI for the groove 22 + - `cid` - Content identifier for the groove record 23 + - `blip` reference in ATProto record links to the grooved blip 24 + - Enables cross-platform groove discovery and portability 25 + 26 + ## Community Engagement Types 27 + 28 + - **looks_good** (👍) - Positive community endorsement 29 + - **shit_rips** - Critical community feedback 30 + 31 + ## Schema Fields 32 + 33 + - `uri` - ATProto record URI (e.g., "at://did:plc:user/com.blonk.groove/rkey") 34 + - `cid` - Content identifier for ATProto record 35 + - `author_did` - DID of user who created this groove 36 + - `subject_uri` - ATProto URI of the blip being grooved 37 + - `groove_type` - Either "looks_good" or "shit_rips" 38 + - `blip_id` - Foreign key to the grooved blip 39 + 40 + ## Examples 41 + 42 + # Groove on a blip 43 + %Groove{ 44 + author_did: "did:plc:user123", 45 + groove_type: "looks_good", 46 + subject_uri: "at://did:plc:author/com.blonk.blip/tech-news", 47 + blip_id: tech_blip.id 48 + } 49 + """ 50 + 2 51 use Ecto.Schema 3 52 import Ecto.Changeset 4 53
+3 -3
lib/elixir_blonk/hot_post_sweeper.ex
··· 54 54 55 55 ## Examples 56 56 57 - # Sweeper finds a trending crypto post 57 + # Sweeper finds a trending tech post 58 58 hot_post = %HotPost{ 59 - text: "New DeFi protocol just launched...", 60 - external_url: "https://protocol.xyz", 59 + text: "Amazing new development framework released...", 60 + external_url: "https://example.com/framework", 61 61 reply_count: 12 # Above threshold! 62 62 } 63 63
+4 -4
lib/elixir_blonk/tags.ex
··· 31 31 32 32 ## Relationship to Blonk Core Concepts 33 33 34 - - **Vibes**: Tags help categorize blips within vibes (e.g., #crypto blips in crypto_vibe) 34 + - **Vibes**: Tags help categorize blips within vibes (e.g., #art blips in art_vibe) 35 35 - **Blips**: Each blip can have multiple tags for cross-vibe discovery 36 36 - **Radar**: Popular tags surface trending content across all vibes 37 37 - **Grooves**: Users groove on tagged content, increasing tag visibility ··· 39 39 40 40 ## Examples 41 41 42 - # Find trending blockchain content across all vibes 43 - blockchain_tag = Tags.get_tag_by_name("blockchain") 44 - trending_blips = BlipTags.get_blips_for_tag(blockchain_tag.id) 42 + # Find trending art content across all vibes 43 + art_tag = Tags.get_tag_by_name("art") 44 + trending_blips = BlipTags.get_blips_for_tag(art_tag.id) 45 45 46 46 # Create a new tag when first used 47 47 {:ok, ai_tag} = Tags.find_or_create_tag("ai", user_did, "Artificial Intelligence")
+4 -4
lib/elixir_blonk/vibes.ex
··· 9 9 ## What Are Vibes? 10 10 11 11 **Vibes are community-driven topic feeds:** 12 - - Interest-based communities (e.g., crypto_vibe, art_vibe, tech_vibe) 12 + - Interest-based communities (e.g., art_vibe, tech_vibe, music_vibe) 13 13 - Created organically through #vibe-name mentions reaching critical mass 14 14 - Contain blips relevant to the community's focus 15 15 - Enable targeted audience engagement and content discovery ··· 71 71 72 72 # Track a potential new vibe 73 73 Vibes.record_vibe_mention(%{ 74 - vibe_name: "defi", 74 + vibe_name: "art", 75 75 author_did: "did:plc:user123", 76 76 post_uri: "at://did:plc:user123/app.bsky.feed.post/rkey", 77 77 mentioned_at: DateTime.utc_now() 78 78 }) 79 79 80 80 # Check if vibe has reached emergence threshold 81 - case Vibes.check_vibe_emergence("defi") do 81 + case Vibes.check_vibe_emergence("art") do 82 82 {:emerging, vibe} -> 83 83 # New community has formed! 84 84 {:not_ready, count} -> ··· 86 86 end 87 87 88 88 # Get vibe content for radar 89 - popular_blips = Blips.list_blips_by_vibe(crypto_vibe.uri) 89 + popular_blips = Blips.list_blips_by_vibe(art_vibe.uri) 90 90 """ 91 91 92 92 import Ecto.Query, warn: false