Texnik tushuntirish · developer / TL

TeleTwin qanday ishlaydi

Bitta ilova, ikki dunyo. Shaxsiy chatlar odatdagidek Telegram serverlariga, korxona chatlari esa o'z serverimizga boradi. Admin xodimni o'chirsa, korporativ qism shu zahoti yo'qoladi, shaxsiy Telegram ishlashda davom etadi.

tdesktop fork · C++/Qt ASP.NET Core · .NET 10 SignalR · WebSockets PostgreSQL 17 Caddy · Docker
Ko'k: Telegram trafigi (MTProto → Telegram DC), tdesktop'ning o'zi
Oltin: korporativ trafik (HTTPS REST + WSS hub → Caddy → teletwin-api → Postgres)
Qizil: revoke (admin → API → WS logout → Corp moduli o'zini tozalaydi)

Manba: README.mddocs/plan.md §4docs/client-contract.md

NimaQayerdanQayergaProtokolKod
Shaxsiy chatlartdesktop MTProto qatlamiTelegram DCMTProto (o'zgarmagan)apiwrap.cpp, mtproto/*
Korxona chatlariCorp::Api (QNetworkAccessManager)https://tele.dtwin.uz/api/*HTTPS REST + JSON, Bearercorp/corp_api.cpp
Real-timeCore::WebSocketClient (QSslSocket)wss://tele.dtwin.uz/hub?access_token=…SignalR JSON protokoli, faqat WebSocketscorp_api.cpp: connectHub, Realtime/CorpHub.cs
AdminBrauzer, /teletwin/admin//api/admin/* (role admin)HTTPS RESTwwwroot/admin/index.html, AdminEndpoints.cs

Default server: DefaultServer() → https://tele.dtwin.uz, TELETWIN_SERVER env bilan almashtiriladi corp_manager.cpp: DefaultServer

02 · So'rovlar yo'li

Interaktiv so'rov tadqiqotchisi

Ssenariyni tanlang: sequence diagramma qadamma-qadam o'ynaydi. Har bir qadamdagi method, path va JSON koddan olingan. Qadamni bosib, uning payload'ini ko'ring.

Qadamlar

    Payload / tafsilot—

    03 · REST + hub

    Endpointlar jadvali

    Hammasi Endpoints/*.cs va Program.cs dan. Token bo'lmasa yoki sessiya o'chirilgan bo'lsa: 401; admin bo'lmagan foydalanuvchi /api/admin/* ga: 403. Tashqi URL'da hammasi /teletwin prefiksi ostida (Caddy uni kesadi).

    MethodPathAuthRequestResponseStatus kodlar
    Program.cs
    GET/healthyo'q—{ status: "ok" }200
    GET/adminyo'q—redirect admin/ → wwwroot/admin/index.html302
    AuthEndpoints.cs
    POST/api/auth/loginyo'q · rate limit login 10/min/IP{ login, password, deviceId }{ accessToken, cacheKey, employee { id, login, fullName, isAdmin } }200 · 401 parol/nofaol · 400 deviceId yo'q · 429
    GET/api/meBearer—EmployeeDto200 · 401 · 404
    POST/api/auth/logoutBearer—faqat shu sessiya (sid claim) o'chadi204 · 401
    ChatEndpoints.cs
    GET/api/chatsBearer—[{ id, title, kind: 1|2, canPost }] faqat a'zo bo'lgan chatlar200 · 401
    GET/api/chats/{chatId}/messages?afterId=&limit=Bearer + a'zoliklimit 1..200 (default 50); afterId bo'lmasa: oxirgi sahifa[{ id, chatId, senderId, senderName, text, sentAt }] o'sish tartibida200 · 404 a'zo emas
    POST/api/chats/{chatId}/messagesBearer + CanPost{ text }MessageDto + hub message → chat:{id}201 · 404 · 403 kanalga huquq yo'q · 400 bo'sh / >4096
    AdminEndpoints.cs · RequireRole("admin")
    GET/api/admin/employeesadmin—[{ id, login, fullName, isActive, isAdmin, activeSessions, chatIds }]200 · 403
    POST/api/admin/employeesadmin{ login, fullName, password, chatIds, isAdmin }AdminEmployeeDto201 · 400 parol < 8 · 409 login band
    POST/api/admin/employees/{id}/passwordadmin{ password }—204 · 400 · 404
    POST/api/admin/employees/{id}/revokeadmin—{ sessions, connections } + hub logout + Abort200 · 400 o'zini · 404
    POST/api/admin/employees/{id}/restoreadmin—IsActive = true204 · 404
    GET/api/admin/chatsadmin—[{ id, title, kind, memberIds }]200
    POST/api/admin/chatsadmin{ title, kind }AdminChatDto, yaratuvchi a'zo + chats_changed201 · 400
    PUT/api/admin/chats/{id}/membersadmin{ employeeIds }AdminChatDto; qo'shilgan/chiqarilganlarga chats_changed, guruhlar jonli yangilanadi200 · 404
    Realtime/CorpHub.cs · MapHub(Transports = WebSockets)
    WS/hub?access_token=token query'da (faqat /hub uchun)invoke Ready()qaytaradi employee id · eventlar: message MessageDto, logout { reason: "access_revoked" }, chats_changed101 · 401

    backend/src/TeleTwin.Api/Endpoints/AuthEndpoints.csChatEndpoints.csAdminEndpoints.csContracts.csAuth/SessionAuthHandler.cs: ReadToken

    04 · Asosiy hiyla

    Server xabari qanday qilib Telegram chat qatoriga aylanadi

    tdesktop UI faqat MTProto obyektlarini taniydi. Shuning uchun Corp moduli serverdan kelgan JSON'ni lokal sun'iy MTP_channel / MTP_user / MTP_message / MTP_dialog ga aylantirib, tdesktop'ning o'z data qatlamiga beradi. Oddiy UI ularni oddiy chatdek chizadi.

    01 · JSON

    MessageDto (server)

    { "id": 57, "chatId": 2,
      "senderId": 3,
      "senderName": "Aziz Karimov",
      "text": "Salom!",
      "sentAt": "2026-…" }

    hub message yoki REST

    02 · PARSE

    Corp::MessageInfo

    ParseMessage(obj)
    .id     = 57
    .chatId = 2
    .date   = sentAt
      .toSecsSinceEpoch()

    corp_api.cpp

    03 · MTP

    prepareMessage → MTP_message

    MTP_message(flags,
     MTP_int(57),
     from = UserFor(3),
     peer = ChannelFor(2),
     date, MTP_string(text) …)

    kanal: f_post | f_post_author

    04 · DATA

    Data::Session / History

    processUser(MTP_user)
    processChat(MTP_channel)
    history->addOlderSlice()
    applyDialogs(MTP_dialog)
    addNewMessage(…, Unread)

    tdesktop'ning o'z API'si

    05 · UI

    Chat ro'yxati

    Hammasi
    💼
    Korxona
    UG
    Umumiy guruhAziz: Salom!
    10:41
    KE
    Korxona · E'lonlarkanal · faqat admin
    09:02

    corp/corp_manager.cpp: prepareMessage, PrepareChannel, PrepareUser, PrepareDialog, applyInitial, applyLivecorp/corp_api.cpp: ParseMessage

    Ajratilgan id diapazoni

    Haqiqiy Telegram id'lari 234 dan kichik. Corp peer'lar 48-bitli id maydonining eng oxirgi 232 ta qiymatini oladi, shuning uchun hech qachon to'qnashmaydi va IsCorpPeer() bitta taqqoslash bilan aniqlanadi.

    kIdSpaceEnd = 1 << 48
    0
    − (1 << 32)
    0
    = kCorpBase
    0
    ChannelFor(chatId = 2)
    0
    0
    2^34 · Telegram id'lari < bu
    2^48 · corp: [2^48−2^32, 2^48)

    O'q log2 shkalada. corp/corp_ids.h: kIdSpaceEnd, kCorpBase, IsCorpBare, ChannelFor, UserFor, ChatIdOf

    Xaritalash qoidalari

    Servertdesktop obyekti
    kind = 1 GroupMTP_channel + f_megagroup
    kind = 2 Channelf_broadcast | f_signatures; xabar post_author = senderName
    kanal + canPostchatAdminRights(post | edit | delete)
    guruh + !canPostdefault_banned_rights(send_messages | send_media | send_plain)
    chat ro'yxatdan chiqdif_left + History::clear(DeleteChat)
    xodim (sender)MTP_user(UserFor(id)), ism SplitName()
    access_hashdoimiy 0x434F525054574E31 = ASCII "CORPTWN1"
    Korxona folderChatFilters::setLocal, id 0x40000000, sarlavha "Korxona", emoji 💼

    Lokal folder serverga ketmaydi

    Telegram folder'larni o'zi sinxronlaydi va noma'lumini o'chiradi. Shuning uchun data_chat_filters.cpp ga lokal id'lar to'plami qo'shilgan: received() sinxrondan oldin takeLocal() bilan chiqarib, keyin restoreLocal() bilan qaytaradi; applyOrder() server tartibiga lokal id'larni qo'shadi; saveOrder() esa MTPmessages_UpdateDialogFiltersOrder ga faqat !isLocal(id) larni yuboradi; remove() lokalni o'chirmaydi.

    05 · Xavfsizlik

    Token, parol, DPAPI va to'siqlar devori

    Asosiy tamoyil: revoke darhol ishlasin va korporativ ma'lumot hech qachon Telegram'ga oqmasin.

    Opaque token: serverda faqat hash

    1 · CSPRNG
    —
    Secrets.NewToken()
    2 · token → client
    —
    LoginResponse.accessToken · namuna
    3 · SHA-256 hex
    —
    Secrets.HashToken()
    4 · Sessions.TokenHash
    —
    TeleTwinDb.OnModelCreating

    Har so'rovda SessionAuthHandler: token → SHA-256 → Sessions + Employee.IsActive. JWT yo'q, demak "muddati tugashini kutish" oynasi ham yo'q: sessiya o'chdi = keyingi so'rov 401. Auth/SessionAuthHandler.csAuth/Secrets.cs

    Parol: PBKDF2-SHA256

    100000.<salt16 b64>.<hash32 b64>

    100 000 iteratsiya, 16 bayt salt, 32 bayt hash, CryptographicOperations.FixedTimeEquals. Admin yaratgan parol kamida 8 belgi.

    Client: Windows DPAPI

    CryptProtectData(json,
      L"TeleTwin", …)
    → tdata/teletwin_<userId>.bin

    Har Telegram akkaunti uchun alohida fayl: server, accessToken, cacheKey, employee. Faqat shu Windows foydalanuvchisi ochadi. Revoke/logout'da removeStored().

    Birinchi admin

    Bootstrap__AdminLogin
    Bootstrap__AdminPassword
    Bootstrap__AdminFullName

    Bazada admin bo'lmasa yaratiladi. deploy.sh birinchi deployda .env ga openssl rand parol yozadi (umask 077).

    To'siqlar devori: corp peer Telegram'ga yetib bormaydi

    tdesktop o'z-o'zidan har bir peer uchun Telegram'ga so'rov yuboradi (full info, o'qildi belgisi, draft, typing, link preview…). Corp id bilan bunday so'rov ketsa, Telegram xato qaytaradi va id'lar oshkor bo'ladi. Kodda 17 ta Corp::IsCorpPeer() to'sig'i, bitta yo'naltirish va bitta folder qoidasi bor (brifdagi "~15" dan biroz ko'p).

    Corp peer so'rovi
    sendMessage → TeleTwin server
    MTProto: bloklandi
    Telegram DC

    Revoke vaqt chizig'i (prodda, internet orqali o'lchangan)

    0POST revoke
    91 mslogout event
    1000 msAbortGraceMs
    ~1.1 ssocket yopildi · eski token 401

    O'lchov natijalari brifdan (prod sinovi), kod emas. Mexanizm kodda: AdminEndpoints.cs: revokeRevoke:AbortGraceMs = 1000

    Nega faqat WebSockets

    Long polling'da har poll qayta autentifikatsiya qilinadi. Revoke'dan keyin sessiya o'chgani uchun keyingi poll 401 oladi va logout event yetkazilmay qoladi. WebSocket ulanishi ochiqligicha qoladi, event yetadi, keyin server uni o'zi uzadi. Program.cs: MapHub(o => o.Transports = HttpTransportType.WebSockets)

    Boshqa nazoratlar

    • Login rate limit: 10/min har IP, 429; IP Caddy'ning X-Forwarded-For dan (UseForwardedHeaders).
    • Admin o'zini revoke qila olmaydi (400).
    • API konteyneri tashqariga port ochmaydi: faqat dtwin-prod_default tarmog'ida Caddy orqali.
    • Client har qanday 401 ni logout deb biladi: REST, scheduleReconnect dagi GET /api/me, hub logout.
    • Fork rasmiy update olmaydi: DESKTOP_APP_DISABLE_AUTOUPDATE=ON, crash report o'chiq.
    06 · Production

    Deploy: VPS, konteynerlar, tarmoqlar

    TeleTwin dtwin bilan umumiy Eskiz VPS'da turadi. HTTPS'ni dtwin'ning Caddy'si tugatadi, TeleTwin'ning o'z ikki konteyneri bor.

    Internet tele.dtwin.uz TeleTwin.exe · admin Eskiz VPS (dtwin bilan umumiy) network: dtwin-prod_default (external, compose: edge) network: teletwin_internal dtwin-prod-web-1 Caddy · :443 TLS handle_path /teletwin/* → teletwin-api:8080 flush_interval -1 (WS) dtwin servislari boshqa loyiha dtwin postgres DNS alias: postgres (TeleTwin'niki emas!) teletwin-api ASP.NET Core .NET 10 · :8080 image teletwin-api, USER app edge + internal tarmoqda teletwin-postgres postgres:17-alpine · :5432 healthcheck pg_isready volume pgdata Host=postgres Host=teletwin-postgres ✓

    deploy/docker-compose.ymlbackend/Dockerfilecommit 0e71790 "deploy: point the API at teletwin-postgres, not the ambiguous 'postgres' alias" Caddy bloki dtwin repo'sidagi Caddyfile'da, bu repo'da yo'q: u brifdan olingan.

    Tuzoq: Host=postgres

    Ikkala compose loyihasi bitta dtwin-prod_default tarmog'iga ulangan. U yerda dtwin'ning servisi ham postgres nomi bilan DNS alias oladi, shuning uchun Host=postgres dtwin bazasiga yo'naldi. Yechim: container_name bo'yicha aniq nom.

    ConnectionStrings__TeleTwin:
      "Host=teletwin-postgres;Database=teletwin;
       Username=teletwin;Password=${POSTGRES_PASSWORD}"

    Caddy (dtwin konteynerida)

    handle_path /teletwin/* {
      reverse_proxy teletwin-api:8080 {
        flush_interval -1
      }
    }

    handle_path prefiksni kesadi: API ichida yo'llar /api/…, /hub. flush_interval -1 WebSocket/stream uchun bufersiz uzatish.

    deploy.sh qadamlari

    git status --porcelainbackend/ yoki deploy/ commit qilinmagan bo'lsa to'xtaydi
    tar → scpbin, obj, *.db* siz arxiv; ssh dtwin
    releases/<rev>ochiladi, current symlink yangilanadi
    .envbirinchi marta: POSTGRES_PASSWORD, ADMIN_* openssl rand
    docker compose up -d --build--env-file /opt/teletwin/.env
    Dockerfilesdk:10.0 publish → aspnet:10.0, :8080, Database__Provider=postgres
    db.Database.Migrate()startup'da (postgres); dev'da SQLite EnsureCreated
    healthdocker exec dtwin-prod-web-1 wget teletwin-api:8080/health, 30 × 2 s

    deploy/deploy.shProgram.cs: UsePostgres → Migrate

    07 · Client build

    Build pipeline: 36 stage'dan installer'gacha

    tdesktop'ni Windows'da yig'ish o'zi alohida loyiha: hamma kutubxona (Qt ham) manbadan statik yig'iladi. Bizning skriptlar uni bitta buyruqqa o'raydi.

    VS 2022 BuildTools · MSVC 14.44Windows SDK 10.0.26100PythonQt 6.11.2 statictg_owt (WebRTC)ffmpegopenssl3

    prepare: build-win.cmd prepare → Telegram/build/prepare/win.bat

    Ro'yxat client/prepare.log: [1/36] … [36/36] dan. Fork'dagi o'zgarishlar: 293f74361c prepare: skip breakpad dump_syms on Windowsffefc5ba9d prepare: build qtwebsockets, disable pacman download timeout

    1 · prepare

    build-win.cmd prepare
    → win.bat silent

    ThirdParty/, Libraries/

    2 · configure

    configure.bat x64
     -D TDESKTOP_API_ID=…
     -D TDESKTOP_API_HASH=…
     -D DESKTOP_APP_DISABLE_AUTOUPDATE=ON
     -D DESKTOP_APP_DISABLE_CRASH_REPORTS=ON

    api_id: git-ignored api-credentials.local.cmd

    3 · build

    cd tdesktop\out
    cmake --build . --config Release
      --target Telegram --parallel

    corp/*.cpp CMakeLists.txt:630-636 da

    4 · package

    package-win.ps1 -Version 0.1.0
    → TeleTwin-0.1.0-win64-portable.zip
    → TeleTwin-Setup-0.1.0.exe

    ZIP: TelegramForcePortable; Inno Setup: per-user, admin shart emas

    Brending: rasmiy Telegram bilan to'qnashmaydi

    core/version.h: AppName = AppFile = "TeleTwin", yangi AppId = {DFCABADF-14C0-4CF6-939F-01EB39867F20} (installer'da ham shu) → o'z %APPDATA%\TeleTwin papkasi. Commit 7b7c0796af "Brand data dir and app id as TeleTwin…". Fork'ga rasmiy update kelmasligi kerak: autoupdate configure'da o'chirilgan.

    Haqiqiy build jang hikoyalari

    Global CONFIG env o'zgaruvchisi pacman-key'ni buzdi

    msys2 stage'ida pacman-key --init tizimdagi CONFIG qiymatini o'qib yiqildi. Yechim: o'zgaruvchisiz muhitda ishga tushirish. manba: sessiya tarixi (brif), kodda iz yo'q

    Sekin pacman mirror'lari

    Yuklab olish timeout bilan uzildi → pacman -Syu --noconfirm --disable-download-timeout. prepare.py:543ffefc5ba9d

    ATL yo'q → breakpad dump_syms yig'ilmadi

    BuildTools'da ATL komponenti yo'q edi; crash report baribir o'chiq, shuning uchun Windows'da dump_syms o'tkazib yuborildi. 293f74361c

    C:\msys64 PATH'da: MinGW header'lari MSVC'ga sizdi

    build-win.cmd vcvars'dan oldin C:\msys64\ucrt64\bin, C:\msys64\usr\bin va scoop mingw'ni PATH'dan olib tashlaydi. build-win.cmd:11-13d6d4d6c

    NoDefaultCurrentDirectoryInExePath

    Bu sozlama yoqilganda cmd joriy papkadagi configure.bat ni topmaydi → skript uni to'liq yo'l bilan chaqiradi. build-win.cmd:3167f49d8

    Disk to'ldi: Qt build 22 GB .pch qoldirdi

    Qt 6.11.2 static (Debug + RelWithDebInfo) precompiled header'lari diskni yedi; tozalab, build davom ettirildi. manba: brif, kodda iz yo'q

    08 · Asboblar

    Qaysi asbob nima qiladi

    tdesktop (C++/Qt)

    Client asosi: UI, MTProto, multi-account. Fork teletwin-desktop, branch teletwin, base f985723 (dev, v7.3.3 dan keyin).

    ASP.NET Core

    .NET 10 minimal API: auth, chatlar, admin. TeleTwin.Api.

    SignalR

    Hub /hub, faqat WebSockets: message, logout, chats_changed. Client SignalR JSON protokolini qo'lda gapiradi.

    EF Core

    Npgsql (prod, migratsiyalar) va SQLite (dev, testlar). TeleTwinDb.

    PostgreSQL 17

    teletwin-postgres, volume pgdata, faqat ichki tarmoqda.

    Docker Compose

    Loyiha teletwin: api + postgres, tashqi tarmoq dtwin-prod_default.

    Caddy

    dtwin konteynerida TLS va handle_path /teletwin/* reverse proxy.

    Core::WebSocketClient

    tdesktop ichidagi QSslSocket asosidagi WS client; QtWebSockets moduliga bog'lanmaydi.

    GitHub (gh)

    Ikkala private repo: XakimovNosirbek/teletwin va XakimovNosirbek/teletwin-desktop (submodule).

    Inno Setup

    installer/teletwin.iss: per-user o'rnatuvchi, {localappdata}\Programs\TeleTwin.

    xUnit + TestServer

    12 integratsion test: haqiqiy HTTP va WebSocket orqali CorpFlowTests.cs.

    Headless Chrome · Node · GSAP

    Admin panel tekshiruvi (CDP), shu sahifa va deck animatsiyasi.

    09 · Kod xaritasi

    Fayllar va mas'uliyat

    Yo'lQatorlarMas'uliyat
    backend/src/TeleTwin.Api
    Program.cs85DbContext (Npgsql/SQLite), Session auth scheme, SignalR, ForwardedHeaders, login rate limit, Migrate/EnsureCreated, Bootstrap + DevSeed, static admin, /hub faqat WebSockets
    Endpoints/AuthEndpoints.cs55login, /api/me, logout
    Endpoints/ChatEndpoints.cs69chatlar ro'yxati, tarix (afterId/limit), yuborish + hub push
    Endpoints/AdminEndpoints.cs137xodimlar CRUD, parol, revoke / restore, chatlar va a'zolar
    Endpoints/Contracts.cs21DTO record'lar (wire format)
    Realtime/CorpHub.cs47hub: OnConnectedAsync guruhlar, Ready(), event nomlari
    Realtime/ConnectionRegistry.cs36xodim → jonli ulanishlar (Abort uchun), MembershipNotifier
    Auth/SessionAuthHandler.cs62Bearer / access_token → SHA-256 → Sessions; claims sid, role admin
    Auth/Secrets.cs34PBKDF2, token generatsiya, token hash
    Data/TeleTwinDb.cs · Bootstrap.cs · DevSeed.cs21 · 42 · 34EF model + indekslar; birinchi admin; dev seed
    Domain/Entities.cs56Employee, Session, Chat, ChatMember, Message
    wwwroot/admin/index.html10 KBadmin panel (vanilla JS)
    backend/tests/…/CorpFlowTests.cs19812 ta [Fact]: login, revoke, rate limit, live a'zolik…
    deploy
    deploy/docker-compose.yml · deploy.sh · backend/Dockerfile43 · 48 · 16konteynerlar/tarmoqlar; release + health; multi-stage image
    client/tdesktop/Telegram/SourceFiles (fork)
    corp/corp_ids.h39id diapazoni, IsCorpPeer, kCorpFilterId
    corp/corp_api.h/.cpp120 / 318REST client, SignalR-over-WebSocket (handshake, Ready, ping 15 s, 0x1E freymlar), reconnect backoff 1→30 s
    corp/corp_manager.h/.cpp76 / 584JSON → MTP obyektlar, Data::Session'ga berish, lokal folder, dedupe, wipe, DPAPI saqlash
    corp/corp_box.h/.cpp17 / 112"Korxonaga kirish" oynasi (Server, Login, Parol) va holat oynasi
    apiwrap.cpp7 joysendMessage yo'naltirish; full peer, peer settings, draft, forward, sendFiles, sendFile to'siqlari
    data/data_chat_filters.cpp—setLocal / removeLocal / takeLocal / restoreLocal, applyOrder, saveOrder, contains
    data/data_histories.cpp3 joydialog entry, read request, sendRequest to'siqlari
    api/api_sending.cpp · api_send_progress.cpp · api_chat_participants.cpp2 · 1 · 1media yuborish, typing, self participant
    data/data_peer.cpp · components/sponsored_messages.cpp · history_view_webpage_processor.cpp1 · 2 · 3full update, reklama, link preview
    main/main_session.cpp:276 · main_session.h—sessiya boshida Corp::Manager yaratiladi; session->corp()
    window/window_main_menu.cpp:711—menyuda "Korxona" → ShowCorpBox
    core/version.h · CMakeLists.txt:630-636—brending; corp fayllarini build'ga qo'shish
    client (teletwin repo)
    build-win.cmd · package-win.ps1 · installer/teletwin.iss · README-colleagues.txt—prepare/configure/build; ZIP + installer; hamkasblar uchun qo'llanma
    10 · Halol holat

    Nima isbotlangan, nima hali yo'q

    QismHolatDalil
    Backend API + hubtayyor12 integratsion test (haqiqiy HTTP + WebSocket, TestServer); brif bo'yicha 5/5 ketma-ket barqaror. Bu sahifa uchun qayta yurgizilmadi. CorpFlowTests.cs
    Productionishlayaptitele.dtwin.uz, admin panel headless Chrome'da tekshirilgan; revoke o'lchovi 91 ms / ~1.1 s / 401 (brifdan).
    Client C++ corp qatlamiE2E tekshirilmaganBuild hali davom etmoqda. Fork commit'ining o'zi: 696255a3a4 Corp layer … (WIP, not compiled yet). Joriy client/build.log (2026-10-29 15:46) da corp_box.cpp da 7 ta kompilyatsiya xatosi: C2672 Ui::GenericBox::addRow (40-qator) va C2660 Corp::Manager::login: function does not take 4 arguments (63-qator).
    cacheKey bilan shifrlangan lokal keshhali yo'qServer beradi, client DPAPI faylida saqlaydi, lekin ishlatmaydi: corp xabarlar faqat xotirada turadi, wipe() ularni tozalaydi.
    O'qilmagan/o'qildi holatilokalPrepareDialog da unread_count = 0, read so'rovi data_histories.cpp da lokal yopiladi.
    README holat jadvalieskirgan"7 integration tests", "client not started" deydi; kod 12 test va client qatlamini ko'rsatadi.
    Litsenziyaochiq savolGPL-3.0 (+OpenSSL istisno); tashqariga tarqatish manba ochishni talab qiladi; repo'lar private, yurist tekshiruvi kutilmoqda.

    Keyingi: ovoz/video xabar

    tdesktop yozuvchisi (OGG Opus) qayta ishlatiladi; upload endpoint kerak.

    Keyingi: fayllar

    MinIO (S3) + webFileLoader orqali yuklab olish. Hozir sendFiles corp peer uchun bloklangan.

    Keyingi: qo'ng'iroqlar

    Self-hosted LiveKit SFU, avval webview, keyin native.

    Keyingi: brending

    Ikonka va nomni to'liq almashtirish (Telegram nomi/logosi ishlatilmaydi), o'z update serveri.