diff --git a/.github/workflows/build-apk.yml b/.github/workflows/build-apk.yml
new file mode 100644
index 0000000..f01b428
--- /dev/null
+++ b/.github/workflows/build-apk.yml
@@ -0,0 +1,87 @@
+name: Build APK
+
+# Builds the Aether Android APK on every push/PR to main and on demand.
+# Pushing a tag like `v1.0.0` (or a manual run with "release") also publishes
+# the APKs to a GitHub Release.
+#
+# Supabase credentials are injected at build time via --dart-define and must be
+# configured as repository secrets (Settings -> Secrets and variables -> Actions):
+# SUPABASE_URL, SUPABASE_ANON_KEY
+
+on:
+ push:
+ branches: [main]
+ tags: ['v*']
+ pull_request:
+ branches: [main]
+ workflow_dispatch:
+ inputs:
+ release:
+ description: 'Attach APKs to a GitHub Release'
+ type: boolean
+ default: false
+
+env:
+ FLUTTER_VERSION: '3.22.2'
+
+jobs:
+ build:
+ name: Build release APK
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: temurin
+ java-version: '17'
+
+ - name: Set up Flutter
+ uses: subosito/flutter-action@v2
+ with:
+ flutter-version: ${{ env.FLUTTER_VERSION }}
+ channel: stable
+ cache: true
+
+ - name: Install dependencies
+ run: flutter pub get
+
+ - name: Generate code (freezed / riverpod / isar / json)
+ run: dart run build_runner build --delete-conflicting-outputs
+
+ - name: Analyze
+ run: dart analyze
+
+ - name: Test
+ run: flutter test
+
+ - name: Build split-per-ABI release APKs
+ run: |
+ flutter build apk --release --split-per-abi \
+ --dart-define=SUPABASE_URL="${{ secrets.SUPABASE_URL }}" \
+ --dart-define=SUPABASE_ANON_KEY="${{ secrets.SUPABASE_ANON_KEY }}"
+
+ - name: Build universal release APK
+ run: |
+ flutter build apk --release \
+ --dart-define=SUPABASE_URL="${{ secrets.SUPABASE_URL }}" \
+ --dart-define=SUPABASE_ANON_KEY="${{ secrets.SUPABASE_ANON_KEY }}"
+
+ - name: Upload APK artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: aether-apk
+ path: build/app/outputs/flutter-apk/*.apk
+ if-no-files-found: error
+ retention-days: 30
+
+ - name: Publish to GitHub Release
+ if: startsWith(github.ref, 'refs/tags/v') || inputs.release
+ uses: softprops/action-gh-release@v2
+ with:
+ files: build/app/outputs/flutter-apk/*.apk
+ generate_release_notes: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/README.md b/README.md
index 703fe5f..6e203a8 100644
--- a/README.md
+++ b/README.md
@@ -1,34 +1,80 @@
-# Aether
+
-> Modern social communication with customizable identity, music presence, and secure messaging.
+# ✦ Aether
-Aether is a username-based social messenger — **not** a WhatsApp clone. It combines
-Signal-Protocol end-to-end encrypted messaging with expressive, customizable profiles,
-Instagram-style stories, Discord-style notes, and Spotify-style music presence, all wrapped
-in a glassmorphism UI on a pure AMOLED dark base.
+### Modern social communication with customizable identity, music presence, and secure messaging.
-Built with Flutter + Supabase. Created by **(Itz_Me) / KairoCloud**.
+Aether is a **username-based social messenger** — *not* a WhatsApp clone. It fuses
+Signal-Protocol end-to-end encrypted chat with expressive customizable profiles,
+Instagram-style stories, Discord-style notes, and Spotify-style music presence —
+all wrapped in a glassmorphism UI on a pure-AMOLED dark base.
+
+[](https://github.com/KairoCloud/Aether/actions/workflows/build-apk.yml)
+
+
+
+
+
+
+Crafted by **(Itz_Me) / KairoCloud**
+
+
---
-## Features
-
-- **End-to-end encrypted messaging** — Signal Protocol (`libsignal_protocol_dart`), X3DH session
- setup, one-time prekey replenishment. Ciphertext only ever leaves the device; private keys
- live in secure storage; decrypted plaintext is cached locally in Isar.
-- **Realtime chat** — per-chat Supabase channel: live message inserts, typing indicators, read
- receipts (✓ / ✓✓ / blue ✓✓), reactions, replies, pin, edit, delete, cursor pagination.
-- **Voice messages** — hold-to-record with live waveform + slide-to-cancel; playback with
- waveform seekbar and 1×/1.5×/2× speed.
-- **Media** — image / video / file sharing with full-screen preview.
-- **Profiles** — parallax banner, avatar with animated music ring, badges, bio, social links,
- 8 accent presets + custom hex (propagates through the whole app).
-- **Friends** — search (with mutual counts), requests, accept/block, privacy-aware visibility.
-- **Stories** — image & text stories, full-screen viewer (animated progress bars, hold-to-pause,
- swipe-to-dismiss, reactions, "seen by"), 24h auto-expiry.
-- **Notes** — 60-char status notes with optional music, 24h expiry, home strip.
-- **Music presence** — manual status with animated equalizer + album art.
-- **Notifications** — FCM push + local notifications, presence, unread badges.
+## Table of contents
+
+- [Highlights](#highlights)
+- [Feature tour](#feature-tour)
+- [Download the APK](#download-the-apk)
+- [Tech stack](#tech-stack)
+- [Architecture](#architecture)
+- [Getting started](#getting-started)
+- [Building locally](#building-locally)
+- [CI / APK workflow](#ci--apk-workflow)
+- [Quality gates & conventions](#quality-gates--conventions)
+- [Security model](#security-model)
+- [Roadmap & known limitations](#roadmap--known-limitations)
+- [License](#license)
+
+---
+
+## Highlights
+
+🔒 **End-to-end encrypted** — real Signal Protocol, not a hand-rolled cipher.
+🎨 **Yours to theme** — 8 accent presets + custom hex that re-skins the entire app live.
+🎵 **Music presence** — animated equalizer + album art, on your profile and your notes.
+📖 **Stories & notes** — full-screen viewer and 60-char status notes, both auto-expiring at 24h.
+🪟 **Glassmorphism** — consistent blurred-glass surfaces over a `#0A0A0F` AMOLED base.
+⚡ **Realtime** — messages, typing, and read receipts arrive without a refresh.
+
+---
+
+## Feature tour
+
+| Area | What you get |
+|---|---|
+| **Messaging** | Signal Protocol E2EE · realtime delivery · typing indicators · read receipts (✓ / ✓✓ / blue ✓✓) · reactions, replies, pin, edit, delete · 30-message cursor pagination |
+| **Voice** | Hold-to-record with live waveform + slide-to-cancel · playback with waveform seekbar and 1× / 1.5× / 2× speed |
+| **Media** | Image / video / file sharing with full-screen, zoomable previews |
+| **Profiles** | Parallax banner · avatar with animated music ring · badges · bio · social links · accent color that propagates app-wide |
+| **Friends** | Debounced search with mutual counts · requests · accept / decline / block · privacy-aware visibility |
+| **Stories** | Image & text stories · animated progress bars · tap-to-navigate · hold-to-pause · swipe-to-dismiss · reactions · "seen by" · 24h expiry |
+| **Notes** | 60-char status with optional music · home strip · expand sheet with equalizer |
+| **Music status** | Manual song/artist/art entry · animated equalizer · blurred album-art backdrop |
+| **Notifications** | FCM push + local notifications · presence · unread badges |
+
+---
+
+## Download the APK
+
+CI builds release APKs on every push to `main`.
+
+- **Latest build:** open the [**Build APK** workflow](https://github.com/KairoCloud/Aether/actions/workflows/build-apk.yml) → pick the most recent run → download the `aether-apk` artifact.
+- **Tagged releases:** push a `v*` tag (e.g. `v1.0.0`) and the APKs are attached to a [GitHub Release](https://github.com/KairoCloud/Aether/releases) automatically.
+
+> The workflow produces per-ABI APKs (`arm64-v8a`, `armeabi-v7a`, `x86_64`) plus a universal APK.
+> For most modern phones, install the **arm64-v8a** one.
---
@@ -36,35 +82,44 @@ Built with Flutter + Supabase. Created by **(Itz_Me) / KairoCloud**.
| Layer | Choice |
|---|---|
-| Framework | Flutter (stable) |
+| Framework | Flutter (stable, 3.22+) |
| State | `flutter_riverpod` + `riverpod_annotation` (codegen) |
-| Routing | `go_router` |
+| Routing | `go_router` with auth + profile guards |
| Models | `freezed` + `json_serializable` |
-| Local DB | `isar` (Signal stores + plaintext cache) |
-| Backend | Supabase (Postgres + Auth + Realtime + Storage + Edge Functions) |
+| Local DB | `isar` — Signal stores + decrypted-text cache |
+| Backend | Supabase — Postgres · Auth · Realtime · Storage · Edge Functions |
| Encryption | `libsignal_protocol_dart` |
| Push | `firebase_messaging` + `flutter_local_notifications` |
-| Audio | `just_audio` (playback), `record` (capture) |
+| Audio | `just_audio` (playback) · `record` (capture) |
+| Fonts | `Sora` (headings) + `DM Sans` (body) via `google_fonts` |
---
## Architecture
-Feature-first Clean Architecture. Each feature has `data/` (repositories, datasources),
-`domain/` (entities, repository interfaces), and `presentation/` (screens, widgets, providers).
-Shared building blocks live under `lib/core/` (theme, constants, widgets, services, utils, db).
+Feature-first **Clean Architecture**. Every feature owns its `data/` (repositories,
+datasources), `domain/` (entities, repository interfaces), and `presentation/`
+(screens, widgets, Riverpod providers). Shared building blocks live in `lib/core/`.
```
lib/
-├── core/ # theme, constants, widgets, services (supabase, encryption, media,
-│ # notifications), db (isar), utils, animations
-├── models/ # Freezed data models (AppUser, Message, Story, Note, ...)
-├── providers/ # global Riverpod providers (auth, user, theme, preferences)
-├── features/ # auth, home, chats, friends, profile, social, notifications, settings
-└── routes/ # go_router config + guards
+├── core/
+│ ├── animations/ transitions + reusable effect configs
+│ ├── constants/ colors, sizes, strings, route names
+│ ├── db/ Isar collections + service
+│ ├── services/ supabase, encryption, media, notifications, storage
+│ ├── theme/ AMOLED theme + AetherColors ThemeExtension (accent)
+│ ├── utils/ validators, color/hex, debounce, formatters
+│ └── widgets/ 14 reusable glassmorphism components
+├── models/ Freezed models (AppUser, Message, Story, Note, ...)
+├── providers/ global providers (auth, user, theme, preferences)
+├── features/ auth · home · chats · friends · profile · social
+│ · notifications · settings · media
+└── routes/ go_router config + guards
+
supabase/
-├── migrations/ # schema, RLS, RPCs, storage policies
-└── functions/ # send-notification, clean-expired (Deno edge functions)
+├── migrations/ schema · indexes · RLS · RPCs · storage policies (0001–0008)
+└── functions/ send-notification · clean-expired (Deno edge functions)
```
---
@@ -72,55 +127,106 @@ supabase/
## Getting started
### Prerequisites
-- Flutter SDK (3.22+)
-- A Supabase project
-- (Optional) A Firebase project for push notifications
+- Flutter SDK **3.22+**
+- A **Supabase** project
+- *(Optional)* A **Firebase** project for push notifications
-### 1. Install dependencies
+### 1 · Backend
+Run the SQL migrations in `supabase/migrations/` **in order** (`0001` → `0008`) against your
+Supabase project, then deploy the edge functions in `supabase/functions/` and set their secrets
+(`SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, and `FIREBASE_SERVICE_ACCOUNT` for push).
+
+### 2 · Dependencies & codegen
```bash
flutter pub get
dart run build_runner build --delete-conflicting-outputs
```
-### 2. Apply the database schema
-Run the SQL migrations in `supabase/migrations/` in order (`0001` → `0008`) against your
-Supabase project, then deploy the edge functions in `supabase/functions/`.
-
-### 3. Configure secrets (never hardcoded)
-Provide Supabase credentials at build/run time via `--dart-define`:
+### 3 · Run (secrets are never hardcoded)
```bash
flutter run \
--dart-define=SUPABASE_URL=https://YOUR_PROJECT.supabase.co \
--dart-define=SUPABASE_ANON_KEY=YOUR_ANON_KEY
```
-### 4. (Optional) Push notifications
-Add your platform Firebase config (`google-services.json` / `GoogleService-Info.plist` and
-`firebase_options.dart`). Without it, notifications are silently disabled — the app still runs.
+### 4 · Push notifications *(optional)*
+Add your platform Firebase config (`google-services.json` / `GoogleService-Info.plist` and a
+generated `firebase_options.dart`). Without it, notifications are silently disabled and the app
+still runs.
---
-## Quality gates
+## Building locally
```bash
-dart analyze # 0 issues
-flutter test # unit tests for models, mappers, utils
+# Universal release APK
+flutter build apk --release \
+ --dart-define=SUPABASE_URL=... --dart-define=SUPABASE_ANON_KEY=...
+
+# Smaller, per-architecture APKs
+flutter build apk --release --split-per-abi \
+ --dart-define=SUPABASE_URL=... --dart-define=SUPABASE_ANON_KEY=...
+```
+Output lands in `build/app/outputs/flutter-apk/`.
+
+---
+
+## CI / APK workflow
+
+`.github/workflows/build-apk.yml` runs on every push/PR to `main`, on `v*` tags, and on manual
+dispatch. Each run:
+
+1. sets up Java 17 + Flutter 3.22.2,
+2. installs deps and runs **codegen**,
+3. gates on `dart analyze` + `flutter test`,
+4. builds per-ABI **and** universal release APKs,
+5. uploads them as the `aether-apk` artifact, and
+6. on a `v*` tag (or a manual run with *release* checked) attaches them to a GitHub Release.
+
+**Required repository secrets** (Settings → Secrets and variables → Actions):
+
+| Secret | Purpose |
+|---|---|
+| `SUPABASE_URL` | Your Supabase project URL |
+| `SUPABASE_ANON_KEY` | Supabase anon/publishable key |
+
+> Builds are **unsigned** (debug-signed) by default. To ship a Play Store build, add a release
+> keystore + signing config and wire it into `android/app/build.gradle`.
+
+---
+
+## Quality gates & conventions
+
+```bash
+dart analyze # 0 issues
+flutter test # unit tests: models, RPC mappers, validators, hashing
```
-Project conventions (enforced): sound null-safety, Freezed on every model, `@riverpod` providers,
-constants in `lib/core/constants/`, `ListView.builder` for dynamic lists, 300-line file cap,
-no plaintext logging, no custom crypto.
+Enforced throughout: sound null-safety · `@freezed` on every model · `@riverpod` providers ·
+constants in `lib/core/constants/` · `ListView.builder` for dynamic lists · **300-line file cap** ·
+`const` everywhere allowed · **no plaintext logging** · **no custom crypto**.
+
+---
+
+## Security model
+
+- **Text messages are end-to-end encrypted.** Supabase only ever stores ciphertext; the identity
+ private key never leaves `flutter_secure_storage`; decrypted text is cached on-device in Isar
+ (the Signal ratchet only allows decrypting a message once).
+- **Row Level Security** is enabled on **every** table. Cross-table checks (chat membership,
+ friendship, blocks) go through `SECURITY DEFINER` helper functions to prevent policy recursion.
+- **One-time prekeys** are claimed atomically server-side and replenished when low.
+- **No secrets in source** — all credentials are injected via `--dart-define` / CI secrets.
---
-## Security notes
+## Roadmap & known limitations
-- **Text messages are end-to-end encrypted.** Supabase stores ciphertext only.
-- **Row Level Security** is enabled on every table; cross-table checks use `SECURITY DEFINER`
- helper functions to prevent policy recursion.
-- **Known limitations** (tracked for future work): media blobs are transport-encrypted (HTTPS +
- RLS) but not E2E-encrypted; group messaging is not yet E2E (1:1 only); presence has no
- background teardown/heartbeat.
+- 📎 **Media is not E2E-encrypted** — blobs are transport-encrypted (HTTPS + RLS), text is E2EE.
+- 👥 **1:1 E2EE only** — group sender-key encryption is not yet implemented.
+- 🟢 **Presence has no background teardown** — online status is set on app open; a heartbeat /
+ lifecycle teardown is pending.
+- 🔔 **Push requires Firebase config** — disabled gracefully until added.
---