A private, invite-only social network built for a close circle of friends โ combining AI-powered image generation, end-to-end encrypted messaging, and intelligent post recommendations.
Origin
I built SocialNetwork.Social for my closest friends โ a private social network they could actually trust. Public social platforms are noisy, algorithmically manipulative, and increasingly hostile to genuine connection. I wanted something different: a small, curated space where real friends could share, react, and communicate without ads, surveillance, or strangers.
The project became an opportunity to explore what modern social infrastructure looks like when you're not optimizing for engagement at scale, but for depth and quality of interaction within a small trusted group. I leveraged Cursor and a suite of AI coding tools to write code faster and more effectively, dramatically compressing the development timeline.
Features
Rather than a stripped-down MVP, I built a genuinely feature-rich platform โ each capability chosen because it solves a real frustration with existing social apps.
&username.soundname syntax โ anywhere in a post or comment.Architecture
The platform is a Flask REST API backed by PostgreSQL, with a React SPA frontend built with Vite. Media and generated images are stored on Cloudflare R2 via the S3-compatible boto3 SDK. Real-time messaging is delivered through SpacetimeDB, which acts as the live transport layer for the E2EE chat subsystem.
Technical Deep Dive
Image generation is handled by black-forest-labs/FLUX-1-schnell accessed through DeepInfra's OpenAI-compatible endpoint. The request goes through the standard openai.images.generate call, so swapping the base URL is the only change needed to point at DeepInfra rather than OpenAI directly โ making it trivially cheap.
After generation, the pipeline immediately classifies the image using Gemma multimodal (also on DeepInfra) to generate a set of category scores. These scores power the feed recommendation system โ a generated image can appear in the feeds of users who are interested in its detected topics, just like any other post.
UserImageGenerationStats enforces a cap of 20 generations per user per day before any API call is made.s3_client.upload_fileobj(). A CDN-backed public URL is constructed from the app config's custom domain.{ "Technology": 0.85, "Art": 0.4, โฆ } category scores.Post row is created with the R2 URL, and one PostCategoryScore row is inserted per category โ enabling relevance-based feed ranking.Technical Deep Dive
Ampersounds are re-usable audio clips that any member can embed in posts or comments using a simple &username.soundname syntax. A server-side regex pass over post content resolves each tag against the database and injects a data--attributed span that the React frontend transforms into a playable audio button.
The entire text is HTML-escaped first, before any tag replacement โ ensuring that user-supplied content can never inject raw HTML. Only DB-verified values are placed into element attributes, preventing stored XSS.
Audio files can also be imported directly from YouTube URLs using yt-dlp. The server extracts just the audio track, trims it to a reasonable length, stores it on R2, and enters it into the moderation queue. An admin approval step runs before any sound becomes publicly searchable โ preventing abuse of the ingestion pipeline.
Technical Deep Dive
Every post on the platform is run through Gemma 3 (via DeepInfra) when it's created, producing a JSON object of category-to-score mappings โ e.g. {"Technology": 0.9, "Science": 0.4}. These are persisted as PostCategoryScore rows. Over time, as users engage, a parallel UserInterest table accumulates category affinity scores for each person.
At feed-render time, a single SQL query computes a feed score for every visible post by joining PostCategoryScore against the user's UserInterest weights and folding in four normalized signals:
Recency (D_WEIGHT=0.70) is the dominant signal by design โ the network is small and real-time, so stale posts should decay quickly. Relevance (0.20) personalizes results using the user's top-5 interest categories. Each signal is normalized with a "softplus" denominator (K constants) to prevent any single viral post from monopolizing the feed.
Posts whose detected categories overlap with a configurable blocked categories list are filtered out after pagination โ allowing admins to suppress entire topic areas without changing the core algorithm.
Technical Deep Dive
The chat system implements a full X3DH-style key agreement protocol โ the same cryptographic approach used by Signal. Every registered device has an identity key pair, a signed prekey (rotated periodically), and a pool of one-time prekeys, all generated in the browser using the Web Crypto API and stored exclusively in IndexedDB. The server never receives private key material.
When Alice sends Bob a message for the first time, her client fetches Bob's public key bundle from the server, runs three ECDH agreements (identity ร signed-prekey, identity ร one-time-prekey, etc.), and feeds the concatenated shared secrets through HKDF to derive a symmetric session key. All subsequent messages in the conversation use AES-GCM with that derived key and a freshly generated nonce โ authenticated with associated data (AAD) that binds the ciphertext to its conversation and epoch.
Each encrypted message payload is wrapped in a signed envelope that carries the nonce, AAD, session type, sender identity key, and prekey IDs. The server receives this opaque envelope and routes it to the recipient over SpacetimeDB โ a multiplayer database that acts as the real-time transport layer. The server never holds the session key and cannot decrypt any message.
The system also supports multi-device linking: a secondary device (e.g. a second browser tab) can request a link from an approved primary device. The primary device re-encrypts recent message history and ships it to the new device during the link ceremony โ ensuring the linked device has chat history without the server ever decrypting anything.
Development
I used Cursor as my primary IDE alongside Claude, ChatGPT, and Gemini to write complex subsystems โ especially the E2EE crypto layer and the SQL feed algorithm โ significantly faster than I could alone. The AI tooling was most valuable for researching cryptographic protocols, generating test cases for the Cypress E2E suite, and scaffolding the SpacetimeDB reducers.