Skip to content

ragaa07/Bugit

Repository files navigation

BugIt

A bug tracking Android app built with Jetpack Compose. Capture bugs with screenshots and descriptions, upload them to Google Sheets (organized by daily tabs), with images hosted on ImgBB. Designed for teams that want lightweight, zero-setup bug tracking without the overhead of Jira or Linear.

Demo

BugIt demo

Full quality video

Architecture

Multi-Module Structure

Bugit/
├── :app                    → Entry point, DI root, navigation host, intent handling
├── :core:common            → Utilities, date formatters, extensions
├── :core:data              → Repository interfaces & implementations, connectors
├── :core:database          → Room database, DAOs, entities, database DI module
├── :core:domain            → Use cases (orchestration logic between repositories)
├── :core:model             → Domain models, form config definitions
├── :core:network           → Retrofit clients for ImgBB API, DTOs
├── :core:ui                → Design system: theme, typography, shared Compose components
├── :feature:home           → Home dashboard screen
├── :feature:report         → Bug submission screen with dynamic form
└── :toolbox:googlesheets   → Google Sheets API integration (service account auth, append/tab ops)

Why multi-module? Build times scale with module count, not project size. Changing a feature module only recompiles that module and :app. Feature modules never depend on each other, preventing spaghetti coupling.

Layered Architecture

┌─────────────────────────────────────────────────────┐
│  Presentation  (:feature:*, :app, :core:ui)         │  ← depends on Domain
├─────────────────────────────────────────────────────┤
│  Domain        (:core:domain)                       │  ← depends on Data
├─────────────────────────────────────────────────────┤
│  Data          (:core:data, :core:network,          │  ← lowest layer
│                 :core:database, :toolbox:*)          │
└─────────────────────────────────────────────────────┘

Key Design Decisions

Dynamic Form System

The problem: Bug reports need different fields for different teams. Hardcoding a form means every new field (Priority, Labels, Assignee) requires code changes, rebuilds, and redeployment.

The solution: Forms render from a FormConfig — a serializable list of field definitions. Adding a field means adding an entry to the config. No UI code changes needed.

@Serializable
sealed interface FormFieldConfig {
    val id: String
    val label: String
    val required: Boolean
    val order: Int

    data class Text(...)        // Single-line and multi-line text
    data class ImagePicker(...)  // Single and multi-image selection
    data class Dropdown(...)     // Priority, category, etc.
    data class ChipInput(...)    // Labels/tags with suggestions
    data class DatePicker(...)   // Due dates
}

The Compose renderer uses an exhaustive when block — adding a new field type is a compile error until a corresponding UI component handles it. This makes the system both flexible and safe.

Evolution path:

  • Phase 1: Hardcoded default config
  • Phase 2: JSON stored in DataStore (models are already @Serializable)
  • Phase 3: Remote config endpoint for per-team customization

Extensibility Abstractions

The data layer (:core:data) owns models, interfaces, and implementations. The domain layer (:core:domain) owns use cases that orchestrate them.

// :core:data — models, interfaces, and implementations
interface ImageRepository { ... }           // ImgBBImageRepository
interface BugConnector { ... }              // GoogleSheetsBugConnector (Hilt @IntoSet)
interface BugReportRepository { ... }       // DefaultBugReportRepository (wraps Set<BugConnector>)

// :core:domain — orchestration use case
class SubmitBugReportUseCase(imageRepository, bugReportRepository)

Why? Today BugIt uploads images to ImgBB and writes rows to Google Sheets. Tomorrow it could push to Jira, Notion, or Linear. Adding a connector means implementing BugConnector and adding a Hilt @IntoSet binding — all existing connectors continue to receive submissions automatically.

Data Flow

User fills form → taps Submit
  → ViewModel.submit()
    → SubmitBugReportUseCase(formData, imageUris)
      → Read image bytes from URIs (ContentResolver)
      → ImageRepository.uploadImage(bytes) → ImgBB URL per image
      → BugReportRepository.submitBug(formData, imageUrls)
        → Fans out to all BugConnectors:
          → GoogleSheetsBugConnector: get/create daily tab → append row
          → (Future: JiraBugConnector, NotionBugConnector, etc.)
      → Return Result<SubmissionResult>
    → Update UI: Success / Error

Tech Stack

Layer Choice Why
UI Jetpack Compose + Material 3 Declarative, less boilerplate, first-class animation support
DI Hilt + KSP Compile-time safety, first-class ViewModel injection
Serialization Kotlinx Serialization Kotlin-native, no reflection, multiplatform-ready, KSP codegen
Networking Retrofit + OkHttp Industry standard, multipart upload support for ImgBB
Persistence Room Type-safe SQLite wrapper, Flow-based reactive queries
Sheets Google Sheets Java API Official library, handles service account auth
Images Coil Kotlin-first, Compose-native image loading
Navigation Compose Navigation Official Jetpack solution, type-safe routes
Typography Inter (Google Fonts) Clean, professional dev-tool aesthetic
Architecture Layered (Data → Domain → Presentation) + MVVM Clean separation, use cases orchestrate, features consume

Setup

Prerequisites

  • Android Studio Ladybug or later
  • JDK 11+
  • Android SDK 36 (install via Android Studio SDK Manager)

1. Clone the repository

git clone https://github.com/<your-username>/Bugit.git
cd Bugit

2. Get an ImgBB API key

BugIt uploads bug report screenshots to ImgBB for free image hosting.

  1. Go to https://api.imgbb.com/
  2. Sign up or log in
  3. Your API key is displayed on the page — copy it

3. Create a Google Cloud service account

BugIt writes bug reports to Google Sheets using a service account.

  1. Go to Google Cloud Console
  2. Create a new project (or select an existing one)
  3. Enable the Google Sheets API:
    • Navigate to APIs & Services > Library
    • Search for "Google Sheets API"
    • Click Enable
  4. Create a service account:
    • Go to APIs & Services > Credentials
    • Click Create Credentials > Service Account
    • Name it (e.g. bugit-sheets) and click Done
  5. Generate a JSON key:
    • Click the newly created service account
    • Go to the Keys tab
    • Click Add Key > Create new key > JSON
    • A .json file will download — this is your service_account.json

Alternatively, if you have the gcloud CLI installed:

# Create project and enable Sheets API
gcloud projects create bugit-app --name="BugIt"
gcloud config set project bugit-app
gcloud services enable sheets.googleapis.com

# Create service account and download key
gcloud iam service-accounts create bugit-sheets --display-name="BugIt Sheets"
gcloud iam service-accounts keys create core/network/src/main/res/raw/service_account.json \
  --iam-account=bugit-sheets@bugit-app.iam.gserviceaccount.com

4. Create and share a Google Sheet

  1. Go to Google Sheets and create a new blank spreadsheet
  2. Click Share (top-right corner)
  3. Add the service account email as Editor:
    bugit-sheets@<your-project-id>.iam.gserviceaccount.com
    
    The exact email is in your service_account.json under client_email.
  4. Copy the Spreadsheet ID from the URL:
    https://docs.google.com/spreadsheets/d/<SPREADSHEET_ID>/edit
    

5. Configure local.properties

Add your secrets to local.properties in the project root (this file is gitignored):

IMGBB_API_KEY=your_imgbb_api_key
SPREADSHEET_ID=your_google_spreadsheet_id

6. Place the service account JSON

Copy the downloaded service_account.json to:

core/network/src/main/res/raw/service_account.json

This file is gitignored. The app reads it at runtime via R.raw.service_account.

7. Build and run

./gradlew assembleDebug

Or open the project in Android Studio and run on a device/emulator (API 24+).

Design

Theme

Indigo-Teal professional palette with full dark mode support. Dynamic colors on Android 12+, custom fallback below.

Screens

Home — Command center with hero banner, quick actions, and recent reports list. Extended FAB collapses to icon-only on scroll.

Report — Focused form with horizontal image attachment strip, dynamically rendered fields, and a fixed bottom submit bar with animated state transitions (idle → loading → success → error).

Shared Components

The :core:ui module provides 13 reusable components: top app bar, text fields, text areas, dropdowns, priority selectors, chip inputs, image strips, thumbnails, image source sheet, loading buttons, empty states, and section headers. All follow Material 3 guidelines.

License

TBD

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages