Team Concept → Solo Build · PWA · 0-to-1 · Live Product · 2025
Swaply — Peer Skill Exchange Platform
Swap your skills. Learn for free.
Peer-to-peer skill exchange χωρίς χρήματα — κάθε χρήστης διδάσκει και μαθαίνει ταυτόχρονα. Ξεκίνησε ως ομαδικό ακαδημαϊκό project (3 άτομα· δικά μου τα Figma prototypes + AI agent μέσω Flowstate)· το ανέλαβα μόνος μέχρι production — UX, full-stack engineering, security architecture, CI/CD.
Π.χ. ξέρεις φωτογραφία και θες να μάθεις Excel; Το Swaply σε ταιριάζει με κάποιον που ξέρει Excel και θέλει να μάθει φωτογραφία — chat, κανονίζετε μια online συνάντηση, και μετά αξιολογεί ο ένας τον άλλον, σαν reviews. Καμία πληρωμή σε καμία φάση.
WHY IT MATTERSΤο έχτισα μόνος, από την ιδέα μέχρι ζωντανό προϊόν: μίλησα πρώτα με ανθρώπους για να καταλάβω το πρόβλημα, μετά σχεδίασα και έγραψα όλο τον κώδικα.
~3,800
Lines of Code
6
User Interviews
4
Cache Layers
2
Shipped → Replaced
The Problem
Γιατί υπάρχει αυτό το product
Ήθελα να μάθω UI design, μπορούσα να διδάξω React — αλλά κανένα product δεν έκανε αυτή την ανταλλαγή frictionless. Post στο Reddit, απάντηση τρεις εβδομάδες μετά — είχα ήδη προχωρήσει. Core insight: αφαιρώντας τα χρήματα φεύγει το payment friction, το regulatory overhead, και η power imbalance teacher/student — όλα μαζί.
Structural moat: Κανένα product δεν συνδυάζει free access + zero money + algorithmic matching. Free = χωρίς matching. Matching = χρεώνει. Χωρίς χρήματα = μόνο γλώσσες.
User Research
6 συνεντεύξεις πριν γραφτεί μία γραμμή κώδικα
6 informal συνομιλίες (3 in person, 3 Discord) πριν γραφτεί κώδικας — όχι τι θα ήθελαν, αλλά τι έκαναν πραγματικά.
Post στο Reddit, reply τρεις εβδομάδες μετά. Είχα ήδη προχωρήσει.
Της έστειλα DM και ένιωσα άβολα — σαν να λέω "stalkarα τη δουλειά σου, θέλω κάτι".
P2 — Graphic designer · Taught Figma, wanted copywritingCold outreach σε strangers = υψηλό social κόστος.
Δύο sessions και μετά σταμάτησε. Ποτέ δεν συμφωνήσαμε σε schedule — πάντα "κάποτε", που σημαίνει ποτέ.
P3 — Language teacher · Spanish tandemInformal agreements διαλύονται χωρίς structure.
Πήγε καλά μόνο γιατί κοινός φίλος μας έσμιξε. Online, δεν θα την εμπιστευόμουν αρκετά για καφέ.
P5 — Marketing student · Taught social media, wanted ExcelTrust είναι το conversion blocker, όχι η discovery.
Caveat: 6 συνομιλίες, όλοι από το δίκτυό μου — όχι statistically significant.
User Personas
3 archetypes ορισμένα από failure modes — όχι demographics
The Skill Trader
Research basis: P1, P4
Clear skill να δώσει/πάρει. Post public, μηδέν signal, εγκατέλειψε πριν match.Blocker: Discovery latency — η θέληση decays πριν βρεθεί κάποιος.Response: Swipe deck · inline match explanation · skill overlap ορατό χωρίς query.
The Burned Exchanger
Research basis: P3, P6
Matched, αλλά exchange κατέρρευσε — "ας το κάνουμε κάποτε" δεν είναι commitment mechanism.Blocker: Scheduling fallthrough — informal agreements χωρίς shared artefact.Response: Session proposal card · Accept/Decline · persistent artefact και για τους δύο.
The Trust-Gated Lurker
Research basis: P2, P5
Open σε exchange, αλλά cold-outreach έχει δυσανάλογο social κόστος — commit μόνο αν trust signal ορατό πριν το contact.Blocker: Cold-outreach anxiety — format of ask kills it before it starts.Response: Ratings visible pre-match · mutual opt-in · AI icebreakers.
Πώς interact: Trader → match volume. Burned Exchanger → session completion + review data. Trust-Gated Lurker ωφελείται από το reputation layer που παράγουν οι άλλοι δύο — γι' αυτό τα ratings είναι infrastructure στο v1, όχι v2 feature.
Problem–Solution Fit
Κάθε feature υπάρχει γιατί κάποιος είπε ότι χωρίς αυτό κάτι κατέρρευσε
User Pain
Feature Response
Success Signal
P1: Post στο Reddit, reply 3 εβδομάδες αργότερα — είχε ήδη προχωρήσει.
Swipe deck με inline match score. Time-to-first-candidate: seconds.
Match-to-chat rate >40%
P2: Cold DM ένιωσε transactional.
Mutual opt-in + AI icebreakers με skill context.
AI icebreaker click-through rate
P3: Exchange κατέρρευσε — ποτέ δεν συμφώνησαν σε schedule.
Session proposal card: date, time, duration, Accept/Decline.
Chat-to-session rate >30%
P5: Εμπιστεύτηκε μόνο γιατί common friend vouched.
Star ratings ορατά στο swipe card — αντικαθιστούν τον voucher.
Review completion >60%
P6: 30+ messages για να οργανώσουν τι θα κάνουν.
Session proposal αντικαθιστά 30 unstructured messages με 1 card.
Avg messages before proposal
The Five-Step Engagement Loop
Κάθε completed swap παράγει data που βελτιώνει τα επόμενα matches
1
Discover
Swipe deck
→
2
Match
Mutual opt-in
→
3
Chat
Real-time
→
4
Swap
Session done
→
5
Review
Star rating
Review → Discover feedback loop: higher-rated users surface earlier in the swipe deck.
Core Features
Τι κάνει το Swaply — και γιατί κάθε feature είναι εκεί
⇄
Skill-Based Swipe Deck
SwipeDeck.jsx · match scoring
Animated card stack, inline MatchScore 1–4 (Partial → Perfect). Free tier: 10 swipes/day enforced στο Firestore rule level, όχι client. Swipe > search: surfaces matches κανείς δεν θα έψαχνε.
MatchExplanationScore 1–410/day @ DB levelScarcity (Cialdini)
msg
Real-Time Chat
~2,100 lines · Chat.jsx
Visibility-aware polling — παύει σε hidden tabs, zero background calls. 2,000 char limit · 500ms anti-spam debounce · read receipts via seen_by · smart date separators.
visibilitychange500ms debounceonSnapshot
cal
Session Proposals
ProposeSession.jsx · P3+P6 research
Structured message: date/time/duration/format/notes → Accept/Decline card inline στο chat. Καμία dedicated screen σκόπιμα — η coordination context μένει στο thread.
In-threadAccept/Decline3 required fields
AI
AI Reply Suggestions
LLaMA 3 · groqProxy · Shipped twice
Skill-aware prompting: injects και τα δύο skill profiles, surface το specific overlap. Generic icebreaker ήταν live 1 μέρα πριν pulled — έλυνε το γενικό blank-canvas problem, όχι το δικό μας. Key μέσω Firebase Secret.
Context-awareFirebase Secret<1s P90
★
Reviews & Reputation
P5 research · Atomic write
Star ratings 1–5 + optional comment. Single atomic Firestore write — no read-modify-write cycle, no race window. Unique constraint reviewer_id + match_id στα rules. Modal fires on "mark complete".
Μόνο access gate (10 swipes/day) — όχι core features, που θα υποβάθμιζαν το reputation loop για όλους. Upgrade έρχεται μετά την αξία, όχι πριν.
Access gate30-day trialHighest-intent cohort
Usability Testing
First Click Test — 10 χρήστες, 3 tasks, πριν το production ship
Πριν κλειδώσει το production layout, έτρεξα ένα δομημένο first-click test: 10 πραγματικοί χρήστες, 3 core tasks, χωρίς καθοδήγηση. Μέτρησα first-click accuracy (πάτησαν το σωστό στοιχείο πρώτη φορά;) και μια 1–5 self-reported ease rating ανά task.
10
Συμμετέχοντες
3
Core Tasks
4.3/5
Μέση Βαθμολογία
86.7%
First-Click Accuracy
Task
First-Click Accuracy
Avg. Rating
Ξεκίνα ένα swap request από το swipe deck
90%
4.6/5
Βρες πώς γίνεσαι "Pro"
100%
4.8/5
Άνοιξε το προφίλ σου / δες τα μηνύματά σου
70%
3.6/5
Εύρημα: Το "Become a Pro" CTA αναγνωρίστηκε άμεσα από όλους τους συμμετέχοντες — καθαρό μήνυμα, καθαρή θέση. Αλλά 3/10 μπέρδεψαν το εικονίδιο προφίλ με το εικονίδιο μηνυμάτων στο task 3, καθυστερώντας το click κατά μέσο όρο ~4 δευτ. Πρόταση: οπτική διαφοροποίηση (icon shape ή badge) ανάμεσα στα δύο, όχι μόνο θέση στο nav.
Service Worker + Web App Manifest · iOS & Android verified · offline-capable
Database Abstraction (db.js, ~1,200 γραμμές): Wraps το Firestore πίσω από Supabase-compatible query API, ώστε κανένα component να μην κάνει import το Firestore SDK απευθείας — μετάβαση σε Supabase = αλλαγές σε ένα αρχείο. Θα επέλεγα Supabase για v2: relational data model ταιριάζει καλύτερα.
4-Layer Cache: IndexedDB (session) → in-memory LRU 5min → per-thread message cache 5min → auth token cache 55min με proactive refresh. ~60–70% read suppression — επεκτείνει το Firestore free tier από ~500 σε ~1,250–1,600 DAU.
Security Architecture
Rules-first · trust boundary στη βάση δεδομένων, όχι στην εφαρμογή
Τα Firestore security rules σχεδιάστηκαν πριν γραφεί UI. Application-layer checks είναι UI, όχι security — αφαιρούνται από DevTools σε <10 δευτ. Τα rules είναι το contract.
Owner updateaffectedKeys().hasAny() whitelist μπλοκάρει is_pro & pro_trial_ends_at. DevTools injection: reject στο DB level.
Trial expiryΜόνο true → false flip μετά το trial timestamp. Reverse από client αδύνατο.
Swipe quotaFree cap (swipes_today < 10) enforced στο rule, όχι client — δεν αφαιρείται ποτέ.
Groq API keyFirebase Secret, accessible μόνο στο groqProxy function. Κάθε request: valid ID token. Verified με strings inspect στο production build.
Shared-device safetycache.clearAll() πριν resolve το signOut(). Επόμενος χρήστης στο ίδιο browser: πάντα cold cache.
match /profiles/{userId} {
allow update: if// Case 1 — owner, must NOT touch Pro fields
(isOwner(userId) &&
!request.resource.data.diff(resource.data).affectedKeys()
.hasAny(['is_pro', 'pro_trial_ends_at']))
||// Case 2 — trial expiry: true → false only
(isOwner(userId) && resource.data.is_pro ==true&&
request.resource.data.is_pro ==false)
||// Case 3 — post-swap rating recalc by any signed-in user
(isSignedIn() && request.resource.data.diff(resource.data)
.affectedKeys().hasOnly(['rating', 'review_count']));
}
Product Decisions & Trade-offs
Τα amber blocks = shipped, pulled, rebuilt — η πιο honest signal
D1Swipe UX αντί για search-and-filter
Search απαιτεί να articulate τι θέλεις πριν δεις τι υπάρχει. Skill exchange είναι serendipitous — το best match μπορεί να είναι κάτι που δεν θα έγραφες ποτέ. Lower per-action cost = higher throughput = more signal.
Cost: Power users δεν πηδάνε κατευθείαν — deliberate, profile search είναι v1.1 Pro feature.
D3Access gate (swipe cap) αντί για feature gate
Gating session proposals ή reviews θα υποβάθμιζε το reputation loop για όλους — paying και free users. Το cap χτυπάει τον highest-intent cohort ακριβώς μετά που βρήκε αξία.
Cost: Low-volume users παίρνουν full value indefinitely — αποδεκτό, volume correlates με willingness to pay.
D7 · Shipped → ReplacedFollow/connections model → Direct-to-chat
Πρώτη εκδοχή: Mutual match δημιουργούσε follower/connections state πριν ανοίξει το chat. Λάθος: Intermediate state πάνω σε ήδη ισχυρό bilateral signal — πρόβλημα που έφτιαξε το ίδιο το product.
Κόστος: 2 μέρες UI work + connections collection — removed πλήρως. Pattern-matching σε familiar social mechanics είναι fast path στο wrong design.
Πρώτη εκδοχή: Generic openers, live για 1 μέρα. Λάθος: Έλυνε το γενικό blank-canvas problem — όχι το δικό μας. Generic opener discards το μοναδικό signal που κάνει το match meaningful.
Κόστος: 2 ώρες rebuild. "Ship fast" είναι καλή συμβουλή μόνο αν αυτό που ship δεν αντικρούει το product thesis.
A/B Experiment — Persuasion Design
Reciprocity (Cialdini) στο onboarding CTA — μετρήσιμο +20%
Ίδια ομάδα με το first-click test, δύο εκδοχές του "Start Learning" CTA στο onboarding. Control: μόνο το κουμπί. Variant: μια γραμμή πριν το κουμπί, framed γύρω από reciprocity — "Κάποιος ήδη περιμένει να μάθει αυτό που ξέρεις." Μέτρηση: 1–5 πόσο πιθανό θα το πατούσαν.
Control
[Start Learning]
3.5/5
→+20%
Variant · Reciprocity
"Κάποιος ήδη περιμένει να μάθει αυτό που ξέρεις." [Start Learning]
4.5/5
Cialdini — Reciprocity: η υπόσχεση ότι κάποιος ήδη "δίνει" πρώτος (θέλει να μάθει από σένα) μειώνει το activation friction πιο αποτελεσματικά από ένα generic CTA. Small sample (n=10) — δεν είναι statistically robust, αλλά η κατεύθυνση ταιριάζει με τη βιβλιογραφία.
GUI vs. Chatbot — Comparative UX Evaluation
Έχτισα εναλλακτικό conversational prototype (AI agent, Flowstate) και το σύγκρινα με το GUI σε 5 Nielsen heuristics
Πέρα από το swipe-based GUI, έφτιαξα και ένα conversational alternative — AI agent μέσω Flowstate που κάνει matching και coordination μέσω free-text chat αντί για UI components. Δομημένη σύγκριση, ίδιο core flow, 5 Nielsen heuristics.
Heuristic
GUI (Swipe + Chat)
Chatbot (Flowstate agent)
Verdict
Error Correction
Structured fields · inline validation · ένα tap για undo
Free text · λάθος intent σημαίνει re-prompt από την αρχή
GUI
Video Call Handoff
Session proposal card κρατά context + link inline
Καμία native επιφάνεια — σπάει το flow σε άλλο εργαλείο
GUI
Navigation Efficiency
1 gesture ανά decision, σταθερό IA
Γρήγορο για one-off ερωτήσεις, αργό για επαναλαμβανόμενες ενέργειες
Split
Visibility of System Status
Persistent nav · match score badge · read receipts πάντα ορατά
Status θαμμένο στο scrollback — εύκολο να χαθεί το πού βρίσκεσαι
GUI
Consistency & Standards
Ίδιο interaction pattern κάθε session
Output ποικίλλει ανά prompt/μοντέλο — λιγότερο προβλέψιμο
GUI
Κατεύθυνση: Το GUI κέρδισε σε 4/5 heuristics — το core loop (matching, scheduling, trust) χρειάζεται structure, όχι conversational flexibility. Το chatbot κέρδισε μόνο σε ένα σημείο: γρήγορες, one-off ερωτήσεις. Αυτό το finding είναι ο λόγος που το AI στο production δεν είναι standalone conversational surface — είναι AI Reply Suggestions μέσα στο ίδιο το chat, στοχευμένο ακριβώς σε αυτό το ένα σημείο όπου το conversational μοντέλο κερδίζει.
Competitive Landscape
Κανείς δεν συνδυάζει και τα τρία
Platform
Pricing
Free
No Money
Skill Matched
Coursera / Udemy
$49–300/course
✗
✗
✗
Meetup / Reddit
Free
✓
✓
✗
Tandem / HelloTalk
Free / $10–20/mo
✓
✓
Language only
Swaply
Free / €9.99/mo Pro
✓
✓
✓ All skills
Reflections
Τι άλλαξε στον τρόπο σκέψης — όχι ανακεφαλαίωση decisions
01
Ξεκίνησα ως engineer που προσποιούνταν ότι κάνει product work.
Είχα ήδη σχεδιάσει το chat screen όταν ο P3 μου είπε για το exchange που κατέρρευσε επειδή "ποτέ δεν συμφωνήσαμε σε schedule". Όχι session proposal, όχι reputation layer — μόνο chat screen. 2 μέρες UI work, κάδος.
Research = constraint, όχι gate. Constraint διαμορφώνει το design θέλεις δεν θέλεις· gate απλά το περνάς και το ξεχνάς.
02
Νόμιζα ότι το "ship fast and iterate" ήταν φιλοσοφία. Αποδείχθηκε excuse.
Ο generic icebreaker (βλ. D8) shipped σε ένα απόγευμα και pulled την επόμενη μέρα — όχι από complaints, αλλά γιατί υπονόμευε αυτό που ήθελε να είναι το Swaply.
"Ship fast" ισχύει μόνο αν δεν αντικρούει το product thesis σου. Όταν το κάνει, η ταχύτητα δεν είναι asset — είναι liability.
03
Έμαθα τη διαφορά μεταξύ feature cut και scope decision.
14 planned features (video calls, calendar sync, group swaps) — όλα με real user research signal. "Cutting video calls" δεν σημαίνει "ποτέ" — σημαίνει "η marginal gain δεν δικαιολογεί 3–4 εβδομάδες WebRTC πριν validate το core loop".
Κάθε cut item έχει condition. Δεν ξέρω ακόμα αν είναι real — αυτό δεν είναι μικρότερη φιλοδοξία, είναι πιο honest.
04
Το cold-start problem με δίδαξε ότι το trust είναι το actual product.
Το seed.js έγραφε 12 demo personas — ονόματα, skill combinations, chat histories, reviews. Αυτό με ανάγκασε να ρωτήσω: πώς μοιάζει επιτυχημένος Swaply user στο τέλος ενός completed swap; Οι απαντήσεις έγιναν ο bar που έπρεπε να ξεπεράσει το product.
Social proof δεν είναι marketing trick. Για two-sided platform με trust barrier, είναι load-bearing infrastructure.
Roadmap
Blocked on validation data — όχι απλά "cut"
v1.1 — Near Term
In-app video calls (WebRTC/Daily.co) — removes Zoom friction
Synonym normalisation — "JS" = "JavaScript" via AI
v1.2 — Mid Term
Push notifications — D7 retention gap για dormant users
Calendar export — manual copy-paste αποδεκτό friction στο v1
Async video clips — session preview
v2.0 — Long Term
Group swaps / 3-way exchanges — blocked on core loop validation
Native iOS & Android — PWA αρκεί τώρα
Institutional white-label — blocked on retention track record
Το Swaply είναι η τεκμηρίωση μιας θέσης: ότι product thinking και engineering δεν είναι διαφορετικές φάσεις — είναι η ίδια απόφαση. Η session proposal υπάρχει γιατί ο P3 είπε ότι το exchange κατέρρευσε. Τα atomic rating writes υπάρχουν γιατί η reputation είναι infrastructure. Το db.js abstraction υπάρχει γιατί ήδη ξέρω ότι θα περάσω σε Supabase.
Every product decision should have a clear engineering consequence, and every engineering decision should serve a concrete user outcome.
Σπήλιος Δημακόπουλος · Solo build · React 18 · Firebase · Groq/LLaMA 3 · Vercel · MIT License · 2025