Community platform · TechNarts internship · 2025
Topluluk
A full community platform built solo, with recommendations that come from sentence embeddings rather than popularity.
Why I built it
TechNarts told me: we use Django, so build anything you like, as long as the backend is Django. The first thing that came to mind was a community site. I thought something like Reddit would actually be pretty good, so honestly, my whole motivation was to build an exact copy of Reddit.
What it is
Topluluk means “community” in Turkish. It has communities you can join, topics with threaded comment replies, up- and downvotes, moderators who can remove content and ban users, and live notifications. The backend is Django REST Framework, the frontend is React with TypeScript, and Docker Compose runs the whole stack: PostgreSQL with pgvector, Redis, the API and the UI.
Recommendations from meaning, not popularity
- New content Every topic, comment and community is embedded with Sentence-Transformers (all-MiniLM-L6-v2, 384 dimensions).
- on save
- pgvector The vector is stored in PostgreSQL next to the row it describes.
- You interact Votes count three times their value, views count once, joining a community half.
- update
- Interest vector A running weighted average of everything you’ve interacted with.
- query
- Recommendations The 10 nearest topics you haven’t seen yet, by cosine distance.
The interest vector is updated incrementally: each profile stores the weighted sum and the total weight, so a new interaction is one vector addition rather than a pass over your whole history.
def update_interaction(self, interaction_embedding, weight):
if self.weighted_sum_vector is not None:
ws_vec = np.array(self.weighted_sum_vector)
else:
ws_vec = np.zeros(384)
tw = self.total_weight
ws_vec += weight * np.array(interaction_embedding)
tw += weight
self.weighted_sum_vector = ws_vec.tolist()
self.total_weight = tw
self.interest_vector = (ws_vec / tw).tolist()
self.save() Ranking then happens inside the database: pgvector orders topics by cosine distance to the interest vector, after excluding everything you’ve already clicked or voted on.
The rest of the platform
- Hot topics: topics from the last 24 hours, ranked by views plus five times their votes.
- Live notifications: a WebSocket per signed-in user through Django Channels, with Redis as the channel layer.
- Moderation: per-community moderators, with permissions for removing topics and comments and banning users.
- Auth: JWT, with the refresh token kept in a cookie.