# Ikar Ikar is a working Telegram-like messenger MVP built in this folder with an ASP.NET Core backend, an Android MAUI client, and a dedicated WinUI 3 desktop client for Windows. ## Stack - `src/Ikar.Server`: ASP.NET Core 10 Web API + SignalR + SQLite. - `src/Ikar.Shared`: shared DTO/contracts used by server and client. - `src/Ikar.Client`: .NET MAUI client targeting `net10.0-android`. - `src/Ikar.WinUI`: WinUI 3 desktop client targeting `net10.0-windows10.0.19041.0`. ## Implemented - phone-based sign-in with one-time test codes - JWT access tokens with rotating refresh tokens - secure client-side session persistence - seeded demo accounts and sample chats - Android contact-book lookup against registered phone numbers - direct chats - group chats - channels with owner-only publishing - message history persisted in SQLite - file attachments with metadata persisted in SQLite - voice notes as audio-classified attachments - inline voice note playback in Android chat - message edit/delete with realtime updates - authenticated attachment download - real-time message delivery with SignalR - Android direct-chat audio/video calls with SignalR-based signaling and WebRTC media transport - dedicated Android call screen for incoming and outgoing audio calls - Android call ring/ringback tones and proximity-based screen blanking during active calls - Android push registration API and FCM-based push delivery pipeline - web admin panel for users, chats, attachments, and system status - public landing page at `/` with latest Android APK download - publishable Windows `exe` - publishable Android `apk` ## Not Implemented This is not full Telegram parity. The following are not implemented in this MVP: - microphone recording UI for voice notes - stickers and inline media previews - end-to-end encryption - advanced channel admin roles, granular moderation policies, multi-device sync edge cases - Windows cloud push notifications ## Demo Accounts - `alice`, phone `+10000000001` - `bob`, phone `+10000000002` - `carol`, phone `+10000000003` These are created automatically on first server start in `src/Ikar.Server/Data/ikar.db`. ## Run 1. Start the backend: ```powershell ./scripts/run-server.ps1 ``` 2. Run the Windows client from Visual Studio or CLI: ```powershell dotnet build .\src\Ikar.WinUI\Ikar.WinUI.csproj -f net10.0-windows10.0.19041.0 -p:Platform=x64 .\src\Ikar.WinUI\bin\x64\Debug\net10.0-windows10.0.19041.0\win-x64\Ikar.WinUI.exe ``` 3. Run the Android client from Visual Studio or install the generated APK: ```powershell dotnet build .\src\Ikar.Client\Ikar.Client.csproj -f net10.0-android ``` The Android client is hard-wired to the current production endpoint: - Android client default base URL: `https://ikar.kusoft.xyz` The Android login screen no longer exposes a server URL field. The production Docker deployment binds the backend to `127.0.0.1:5099` on the Raspberry Pi host. Public and LAN clients should use the reverse-proxied HTTPS endpoint instead of direct access to port `5099`: - public Android / browser / admin URL: `https://ikar.kusoft.xyz` ## Run In Docker Docker assets for Raspberry Pi 5 are included in the repo: - `Dockerfile.server` - `docker-compose.rpi5.yml` - `.env.example` - `.env.server` - `docs/raspberry-pi-5-docker.md` Quick start: ```bash cp .env.example .env docker compose -f docker-compose.rpi5.yml up -d --build ``` To place server data on an external disk, set `IKAR_DATA_PATH` before running Compose. The current production Pi uses `/media/myDrive/ikar-data`. Health check: ```bash curl http://127.0.0.1:5099/health ``` Admin panel: - `/admin` redirects to `/admin/index.html` - configure admin login through `Admin__Username` and `Admin__Password` - the admin surface uses its own cookie session and does not reuse messenger JWT tokens - `/` serves a public landing page with a button for the latest Android APK - `/api/app-updates/android/download/latest` returns the latest published Android APK - `scripts/publish-android-update.ps1` keeps only the newest `3` Android APK files on the server by default; override with `-KeepLatestCount ` if needed ## Publish Windows EXE: ```powershell ./scripts/publish-windows.ps1 ``` Android APK: ```powershell ./scripts/publish-android-apk.ps1 ``` Smoke test against the running backend: ```powershell ./scripts/smoke-test.ps1 ``` ## Published Artifacts - Windows EXE: `artifacts/winui-win64/Ikar.WinUI.exe` - Android APK: `src/Ikar.Client/bin/Release/net10.0-android/publish/com.seven.ikar.apk` - Signed Android APK: `src/Ikar.Client/bin/Release/net10.0-android/publish/com.seven.ikar-Signed.apk` ## Solutions - XML solution: `Ikar.slnx` - classic Visual Studio solution: `IkarClassic.sln` ## Auth Notes - Android client auth is currently `phone-only`. - The current verification flow returns a temporary test code from the server and shows it in the client UI. - Real SMS delivery is not implemented yet; it can be connected later by adding an SMS provider. - Access tokens are short-lived JWTs. - Refresh tokens are rotated on refresh and stored as hashed server-side sessions. - Logout revokes the active session immediately, and the revoked access token stops working because the server validates the session id (`sid`) on authenticated requests. - Session `LastSeenAt` writes are throttled server-side to reduce unnecessary SQLite writes on every authenticated request. - The JWT signing key in `src/Ikar.Server/appsettings.json` is a development default. Replace it with a strong secret via configuration before any real deployment. ## Contacts Notes - Android contact discovery requests `READ_CONTACTS` and only shows people from the device phone book. - Server-side contact resolution matches users by normalized phone number through `api/users/contacts/resolve`. - Users without a registered phone number do not appear in the Android contacts screen. ## Attachment Notes - Attachments are stored on the server under `src/Ikar.Server/Data/Attachments`. - Metadata stored for each attachment: original file name, content type, file size, upload time, and owning message. - Audio files are classified as `voice notes` by MIME type / file extension and use the same secure attachment pipeline. - Attachment content is downloaded through an authenticated API route, not via a public static files directory. ## Channel And Message Lifecycle Notes - Channels are broadcast rooms: the creator is the owner, selected users join as subscribers, and only owners can publish. - Message edit/delete is synchronized through SignalR `MessageUpdated` events. - Delete is implemented as a soft-delete on the message row with attachment cleanup on the server. ## Call Notes - Calls are currently implemented only for Android and only in direct one-to-one chats. - The current call architecture uses SignalR for call lifecycle/signaling and WebRTC for audio/video media transport. - ICE servers are configured server-side through the `WebRtc` configuration section. - WinUI does not support calls in the current build. ## Push Setup Notes - Android push in this repo is implemented through Firebase Cloud Messaging HTTP v1 on the server and `FirebaseMessagingService` on the Android client. - Server-side device registrations are stored in SQLite in the `PushDevices` table and managed through `api/push/devices`. - Push dispatch is queued through a background worker so message sends do not wait on outbound Firebase network latency. - To enable real Android delivery, set `Push:FirebaseProjectId` and either `Push:ServiceAccountJsonPath` or `Push:ServiceAccountJson` in `src/Ikar.Server/appsettings.json` or environment-specific configuration. - Before building the Android APK, fill `src/Ikar.Client/Resources/Raw/firebase.android.json` with the Android Firebase values: `applicationId`, `projectId`, `apiKey`, `senderId`. - If the Firebase configuration is left empty, the app still builds and the server still accepts device registrations, but actual FCM delivery is skipped. - The current Windows WinUI desktop target is unpackaged (`WindowsPackageType=None`), so this pass does not implement Windows cloud push. ## Server Runtime Notes - Chat list loading now fetches only the latest message per chat for summary rendering instead of loading full message history. - The server exposes `/health` for container and deployment health checks. - The server exposes `/admin/api/*` plus static admin assets under `/admin/*` when admin credentials are configured. - Startup enables SQLite write-ahead logging and ensures an index on `ChatMembers.UserId` for chat list lookup.