Back to projects

SolveIt

A platform I built for students to exchange academic help and mentoring safely.

This project actually started as one of my university assignments, but I decided to push it much further than what was required. I noticed that student communities often use WhatsApp or Discord to ask for academic help, but it's hard to track tasks and payments aren't always secure. I wanted to see if I could build a centralized, more advanced platform to solve that.

Why I made this

I wanted to solve the friction in peer-to-peer help. By making a dedicated dashboard, students can post what they need help with, and others can bid to mentor them. I used it as a way to practice building a real-world SaaS architecture with proper payment flows and real-time features.

How it works

  • Next.js & Tailwind: The main interface is built with Next.js. I kept the design clean so it's easy to use.
  • Go for Real-time: I built a custom WebSocket hub in Go to handle the chat, notifications, and signalling. I used Go because its concurrency model is perfect for keeping everything in sync without lag.
  • AI Categorization: I integrated OpenAI to help sort the tasks. It reads the student's description and suggests the subject automatically.
  • Payments: I used Stripe to handle the transactions securely, ensuring that mentoring is a safe exchange for everyone.

The WebSocket Implementation

One of the most interesting parts to build was the communication hub. I had to manage different channels for notifications, comments, and mentor chats while keeping track of active connections.

func (h *WsHub) handleWS(w http.ResponseWriter, r *http.Request, appChan chan IncomingMessage) { conn, err := upgrader.Upgrade(w, r, nil) if err != nil { fmt.Println("failed to upgrade conn:", err) return } conn.SetReadLimit(5 << 20) conn.SetReadDeadline(time.Now().Add(pongWait)) conn.SetPongHandler(func(string) error { conn.SetReadDeadline(time.Now().Add(pongWait)) return nil }) channelID := r.URL.Query().Get("channel") if channelID == "" { conn.Close() return } h.mu.Lock() h.conns[channelID] = append(h.conns[channelID], conn) h.mu.Unlock() go h.cleanUp(conn, channelID, appChan) go func() { ticker := time.NewTicker(pingPeriod) defer ticker.Stop() for range ticker.C { h.mu.RLock() stillActive := slices.Contains(h.conns[channelID], conn) h.mu.RUnlock() if !stillActive { return } conn.SetWriteDeadline(time.Now().Add(writeWait)) if err := conn.WriteControl(websocket.PingMessage, nil, time.Now().Add(writeWait)); err != nil { log.Printf("Ping failed for %s: %v (will retry next tick)", channelID, err) continue } } }() log.Println("New connection for channel:", channelID) }

Things I learned

I struggled with database performance as the project grew. I realized that just adding fields to PostgreSQL wasn't enough; I had to learn about proper indexing on mentorId and other foreign keys to keep the dashboard fast. It was a great lesson in how real-time apps put pressure on the database.

What's next

I'm thinking about adding video mentoring using WebRTC so mentors can explain things better, and maybe adding more automated ways to verify the quality of the tutoring.