Swoosh/CLAUDE.md
Paweł Orzech ccd729e82f
feat: show app version in Settings, fix composer NPE crash, bump to v0.2.0
- Settings: shows "Swoosh v0.2.0" at bottom
- Fix: NPE crash in composer error display (AnimatedVisibility exit)
- Version bumped to 0.2.0 (versionCode 2)
- CLAUDE.md: added versioning process documentation
2026-03-19 15:27:58 +01:00

60 lines
3.2 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Swoosh is an Android microblogging client for Ghost CMS. It provides offline-capable post creation, image uploads, link previews, and scheduled publishing via Ghost's Admin API.
## Build & Test Commands
```bash
./gradlew assembleDebug # Build debug APK
./gradlew assembleRelease # Build release APK (ProGuard enabled)
./gradlew test # Run all unit tests
./gradlew app:testDebugUnitTest # Run unit tests for debug variant
./gradlew test --tests "*.MobiledocBuilderTest" # Run a single test class
./gradlew test --tests "*.MobiledocBuilderTest.testBasicTextPost" # Run a single test method
```
Robolectric is used for tests that need Android framework classes. Unit tests include Android resources (`unitTests.isIncludeAndroidResources = true`).
## Architecture
MVVM with Repository pattern, single-module Gradle project.
**Package: `com.swoosh.microblog`**
- **`data/api/`** — Retrofit service (`GhostApiService`), JWT auth (`GhostJwtGenerator`, `GhostAuthInterceptor`), and `ApiClient` singleton with dynamic base URL
- **`data/db/`** — Room database with `LocalPost` entity and `LocalPostDao`
- **`data/model/`** — Three model layers: `GhostPost` (API), `LocalPost` (Room entity), `FeedPost` (UI display). Enums: `PostStatus`, `QueueStatus`
- **`data/repository/`** — `PostRepository` coordinates local DB and remote API; `OpenGraphFetcher` parses link previews via Jsoup
- **`ui/`** — Jetpack Compose screens (Feed, Composer, Detail, Setup, Settings) with ViewModels using `StateFlow`
- **`worker/`** — `PostUploadWorker` (WorkManager) handles offline queue with exponential backoff
**Key data flow:** Posts are saved to Room first → queued for upload → `PostUploadWorker` syncs to Ghost API when network is available.
## Technical Details
- **Auth:** Ghost Admin API keys are split into `id:secret`, secret is hex-decoded for HS256 JWT signing (5-min expiry)
- **Content format:** Posts use Ghost's mobiledoc JSON format, built by `MobiledocBuilder` (supports text paragraphs and bookmark cards)
- **Credentials:** Stored in `EncryptedSharedPreferences` (AES256-GCM) via `CredentialsManager`
- **API client:** Base URL is configured at runtime during setup; `ApiClient` rebuilds Retrofit instance when URL changes
- **Min SDK 26, Target/Compile SDK 34, Kotlin 1.9.22, Java 17**
## Versioning
Version is defined in `app/build.gradle.kts` (`versionCode` and `versionName`).
- **Format:** Semantic versioning `MAJOR.MINOR.PATCH` (e.g., `0.2.0`)
- **`versionCode`:** Integer, increment by 1 on every release (used by Google Play)
- **`versionName`:** Human-readable, shown in Settings screen
**When to bump:**
- **PATCH** (0.2.0 → 0.2.1): Bug fixes, small tweaks, no new features
- **MINOR** (0.2.0 → 0.3.0): New features, UI changes, significant improvements
- **MAJOR** (0.x → 1.0): First stable public release
**Current:** `versionName = "0.2.0"`, `versionCode = 2`
**Process:** When making a release commit, bump both `versionCode` (+1) and `versionName` in `app/build.gradle.kts`. Always bump version when creating a release build or PR.