← Înapoi la blog

Cum am început să scriu un messenger E2E, de unul singur

Martie 2026. Un singur om, un repository gol, X3DH şi Double Ratchet pe hârtie — şi şase luni ca să ajungă în producţie. De ce am acceptat asta şi ce am învăţat în primele două săptămâni.

  • gchat
  • cryptography
  • solo

La mijlocul lui martie 2026 am făcut un repository gol şi l-am numit gchat. Fără echipă, fără investitori, fără „lasă să-ţi ajutăm să împachetezi ideea”. Patru ore mai târziu aveam primul commit — initial protocol sketch.md, o jumătate de pagină de pseudocod X3DH, două linkuri la specificaţiile Signal şi o listă TODO cu optzeci de puncte.

Fac un messenger cu end-to-end encryption. De unul singur. Şi este o decizie asumată.

De ce nu aleg Signal sau Matrix şi trăiesc liniştit

Prima întrebare pe care o pune orice om sănătos la minte. Răspunsul meu e banal, dar sincer: am vrut să văd tot stack-ul cu propriile mâini. Protocolul criptografic — nu ca „apelează o librărie”, ci ca matricea de chei care prinde viaţă în debugger. Logica serverului — nu ca „un backend oarecare”, ci ca model concret de livrare: cozi, idempotenţă, preluduri de chei, garbage collection pentru mesajele neridicate. Clientul — nu ca „păi, Flutter”, ci ca maşină de stări care funcţionează corect la reţea proastă, rotaţii de chei şi notificări de fundal.

Poţi asambla asta din cărămizi gata făcute. Dar atunci nu ştii unde sunt îmbinările tale reale. Iar într-un produs criptografic, îmbinările devin CVE-uri cu număr peste şase luni.

A doua motivaţie e practică. Am vrut un produs în care deciziile le iau eu. Fără rapoarte, fără comitete, fără „hai să revenim la asta la sprintul viitor”. Solo nu înseamnă mai rapid decât o echipă — înseamnă altfel. În linie dreaptă.

Ce am construit în primele două săptămâni

Pentru mine era important să împing imediat bucăţile cele mai riscante în producţie, nu să mai scriu încă o lună „infrastructură”. Aşa că am mers invers faţă de un MVP obişnuit.

  • Zilele 1–3. Protocolul pe hârtie: X3DH pentru handshake, Double Ratchet pentru forward secrecy, AES-GCM-256 pentru payload, Ed25519 pentru semnături, Argon2id pentru derivarea cheii din parolă. Am desenat toate tranziţiile, toate cheile, toate invarianţii.
  • Zilele 4–5. Cutie neagră PyNaCl + cryptography: prototip de schimb de mesaje între două scripturi dintr-un REPL. Încă fără DB şi fără reţea — doar matematica.
  • Zilele 6–9. FastAPI + SQLAlchemy 2.0 async + Postgres: bundle-uri de chei, emiterea prekey-urilor, un relay de bază. Zero funcţionalităţi de business. Scopul — să verific că cheile supravieţuiesc în coloanele de producţie.
  • Zilele 10–14. Prototip Flutter: ecran de chat, unu-la-unu, fără grupuri, fără ataşamente, fără apeluri. Dar cu E2E real pe schema de producţie.

La finalul săptămânii a doua aveam un mesaj plecat de pe un dispozitiv şi sosit pe altul, criptat de client, decriptat de client, şi un server care nu ştia nimic despre conţinut. Asta e esenţa.

Ce s-a dovedit mai greu decât părea

Trei lucruri.

Rotaţia cheilor în condiţii de offline. Când un dispozitiv tace trei zile, Double Ratchet trebuie totuşi să recupereze. Asta m-a obligat să regândesc cum păstrez bundle-ul prekey pe server şi ce înseamnă „expirat”.

Idempotenţa livrării. Clientul retrimite. Backend-ul a aruncat deja mesajul ca să nu multiplice duplicate. Clientul retrimite iar. Ajungi cu un UI care afişează „nelivrat” pentru un mesaj pe care destinatarul l-a citit deja. Soluţia — message_id determinist pe client plus un index de dedup pe server cu TTL.

CallKit pe iOS. Nu-i despre cripto, ci despre sistemul de operare. Apple consideră normal să livreze un push VoIP în 200 ms, în timp ce livrarea ta de sub VPN durează uneori 800. Ce faci? Prelude push prin APNs + fallback prin WebRTC relay-ICE.

Ce rămâne cu mine

Solo nu e eroism. E o altă economie a atenţiei. Nu-ţi permiţi să scrii ceva ce n-o să întreţii. Fiecare abstracţiune, fiecare strat, fiecare fişier e o promisiune pe care o faci variantei tale de peste şase luni.

De aia GChat e scris simplu. Fără plugin-uri, fără „kernels universale”, fără rescrieri spre „o arhitectură şi mai corectă”. Un limbaj pe backend (Python), unul pe client (Dart), un protocol, un model de livrare. Şi totul stă pe un singur server self-managed pe care îl actualizez manual, o dată pe lună.

Dacă ai o întrebare despre cum e construit GChat — scrie-mi pe Telegram. Dacă ai nevoie de un inginer care şi protocolul criptografic ţi-l desenează pe un şerveţel, şi backend-ul ţi-l asamblează, şi APNs-ul cu FCM ţi-l configurează — ai nimerit unde trebuie.

În notele următoare: cum am ales între compatibilitatea Matrix şi un format propriu, de ce am renunţat la MongoDB şi de ce „landing-ul GChat e mai dur decât messenger-ul în sine” nu e un compliment.