Skip to content

panicDev/Technical-Test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Product Sync Desktop Application

A cross-platform desktop application built with Kotlin Multiplatform and Compose Multiplatform that provides full offline/online synchronization with a REST API.

πŸ“š Documentation

This project includes comprehensive documentation to help you get started and understand the architecture:

Document Description Link
πŸ“– README.md Main documentation (you are here) README.md
βš™οΈ SETUP_GUIDE.md Step-by-step installation and setup guide SETUP_GUIDE.md
πŸ—οΈ ARCHITECTURE.md Technical architecture and design patterns ARCHITECTURE.md
πŸ§ͺ TESTING_GUIDE.md Comprehensive testing scenarios TESTING_GUIDE.md
πŸ“‹ PROJECT_SUMMARY.md Complete project overview and summary PROJECT_SUMMARY.md
πŸ”Œ PRODUCTS_API.md API endpoint documentation PRODUCTS_API.md
πŸ“ CANDIDATE_INSTRUCTIONS.md Original project requirements CANDIDATE_INSTRUCTIONS.md

πŸ“– Quick Navigation


πŸ“‹ Features

  • βœ… Offline-First Architecture: Full functionality without internet connection
  • βœ… Automatic Sync: Queue operations offline, sync when online
  • βœ… Real-time Network Detection: Visual indicators for connection status
  • βœ… CRUD Operations: Create, Read, Update, Delete products
  • βœ… Search & Filter: Fast local search capabilities
  • βœ… Queue Management: Persistent queue for offline operations
  • βœ… Modern UI: Material Design 3 with Compose Multiplatform
  • βœ… Error Handling: Robust error handling with retry mechanism
  • βœ… Cross-Platform: Runs on Windows, macOS, and Linux

πŸ—οΈ Architecture

Clean Architecture with MVVM Pattern

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Presentation Layer                β”‚
β”‚  (Compose UI, ViewModels, UI Components)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            Domain Layer                      β”‚
β”‚    (Use Cases, Domain Models, Business       β”‚
β”‚            Logic)                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚             Data Layer                       β”‚
β”‚  (Repositories, API Client, Local Database)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Components

  • Local Database: SQLDelight for type-safe SQL
  • Network Layer: Ktor Client for HTTP communication
  • Dependency Injection: Koin for Dependency Injection
  • State Management: StateFlow and SharedFlow
  • Offline Queue: Persistent operation queue

πŸš€ Getting Started

Prerequisites

  • JDK 17 or higher
  • Gradle 8.x (included via wrapper)
  • Internet connection (for initial setup and dependency download)

πŸ’‘ Need detailed setup instructions? Check SETUP_GUIDE.md for step-by-step guidance.

Quick Start (3 Steps)

  1. Clone the repository
git clone <your-repo-url>
cd ProductSyncApp
  1. Configure your User ID

Open composeApp/src/desktopMain/kotlin/com/android/technicaltest/data/repository/ProductRepository.kt and replace the placeholder:

val userId = "YOUR_USER_ID_HERE" // Replace with your actual userId
  1. Build and run
./gradlew run

πŸ“š For detailed installation steps, see SETUP_GUIDE.md
πŸ§ͺ To verify everything works, follow TESTING_GUIDE.md

πŸ”§ Configuration

API Endpoint

The base URL is configured in ApiClient.kt:

private const val BASE_URL = "https://multitenant-apis-production.up.railway.app"

Database Location

The local database is stored at:

  • Windows: C:\Users\<username>\.productsync\productsync.db
  • macOS: /Users/<username>/.productsync/productsync.db
  • Linux: /home/<username>/.productsync/productsync.db

πŸ“¦ Project Structure

ProductSyncApp/
β”œβ”€β”€ composeApp/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ commonMain/
β”‚   β”‚   β”‚   β”œβ”€β”€ kotlin/com/android/technicaltest/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ data/
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ local/           # Database & local storage
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ remote/          # API client & DTOs
β”‚   β”‚   β”‚   β”‚   β”‚   └── repository/      # Data repositories
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ domain/
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ model/           # Domain models
β”‚   β”‚   β”‚   β”‚   β”‚   └── usecase/         # Business logic use cases
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ ui/
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ component/       # Reusable UI components
β”‚   β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ screen/          # Screen composables
β”‚   β”‚   β”‚   β”‚   β”‚   └── viewmodel/       # ViewModels
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ util/                # Utilities
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ di/                  # Dependency injection
β”‚   β”‚   β”‚   β”‚   └── App.kt               # Main app composable
β”‚   β”‚   β”‚   └── sqldelight/              # SQL schema definitions
β”‚   β”‚   └── desktopMain/
β”‚   β”‚       └── kotlin/com/android/technicaltest/
β”‚   β”‚           β”œβ”€β”€ Main.kt              # Desktop entry point
β”‚   β”‚           └── data/local/
β”‚   β”‚               └── DatabaseFactory.jvm.kt
β”‚   └── build.gradle.kts
β”œβ”€β”€ build.gradle.kts
β”œβ”€β”€ settings.gradle.kts
└── gradle.properties

🎯 Key Features Explained

1. Offline-First Approach

The app works seamlessly offline:

  • All data is stored locally in SQLDelight database
  • Operations (Create, Update, Delete) are queued when offline
  • Queue persists through app restarts
  • Automatic sync when connection is restored

2. Network Monitoring

Real-time connection status:

  • Green: Online and synced
  • Blue: Syncing in progress
  • Red: Offline mode
  • Orange: Sync error (will retry)

3. Queue System

Intelligent operation queuing:

  • Operations are executed in order
  • Failed operations are retried
  • Retry count tracking
  • Error logging for debugging

4. Data Synchronization

Two-way sync mechanism:

  1. Push: Local changes β†’ Server
  2. Pull: Server data β†’ Local database
  3. Conflict Resolution: Server data takes precedence

πŸ§ͺ Testing Guide

Test Scenarios

1. Offline Create

1. Disconnect internet
2. Create a new product
3. Verify product appears in list with cloud-off icon
4. Check pending operations counter
5. Reconnect internet
6. Wait for auto-sync or click sync button
7. Verify product synced (cloud-off icon disappears)

2. Offline Update

1. Disconnect internet
2. Edit an existing product
3. Verify changes saved locally
4. Verify unsynced indicator appears
5. Reconnect internet
6. Verify changes sync to server

3. Offline Delete

1. Disconnect internet
2. Delete a product
3. Verify product marked for deletion
4. Reconnect internet
5. Verify product deleted from server

4. App Restart with Pending Queue

1. Create operations while offline
2. Close the application
3. Reopen the application
4. Verify queued operations persist
5. Connect to internet
6. Verify operations sync automatically

5. Network Recovery

1. Work offline with multiple operations
2. Reconnect to internet
3. Observe auto-sync process
4. Verify all operations completed
5. Check for any errors

πŸ› οΈ Development

Building from Source

# Clean build
./gradlew clean

# Build project
./gradlew build

# Run application
./gradlew run

# Run tests
./gradlew test

# Create distribution package
./gradlew packageDistributionForCurrentOS

Distribution Packages

The app can be packaged for distribution:

# Create native installer for current OS
./gradlew packageDistributionForCurrentOS

Output locations:

  • Windows: composeApp/build/compose/binaries/main/msi/
  • macOS: composeApp/build/compose/binaries/main/dmg/
  • Linux: composeApp/build/compose/binaries/main/deb/

πŸ“š Technology Stack

Technology Purpose Version
Kotlin Programming Language 2.2.20
Compose Multiplatform UI Framework 1.9.0
Ktor Client HTTP Client 3.3.0
SQLDelight Local Database 2.1.0
Kotlinx Coroutines Async Operations 1.10.2
Kotlinx DateTime Date/Time Handling 0.7.1
Material 3 Design System Latest

πŸ›οΈ Design Patterns

Repository Pattern

Abstracts data sources (local DB, remote API) behind a clean interface.

Use Case Pattern

Encapsulates business logic in single-responsibility classes.

MVVM Pattern

Separates UI logic (ViewModel) from UI rendering (Composables).

Observer Pattern

StateFlow for reactive state management.

Singleton Pattern

ApiClient and NetworkMonitor as application-wide singletons.

πŸ“– For detailed architecture information, see ARCHITECTURE.md


πŸ§ͺ Testing

This project includes comprehensive test scenarios covering:

  • βœ… Functional testing (CRUD operations)
  • βœ… Offline/online synchronization
  • βœ… Edge cases and error handling
  • βœ… Performance benchmarks
  • βœ… UI/UX validation

Quick Test

# Test 1: Launch application
./gradlew run

# Test 2: Create product while online
# Click + button β†’ Enter title β†’ Create

# Test 3: Test offline mode
# Disconnect internet β†’ Create product β†’ Reconnect β†’ Verify sync

πŸ§ͺ For complete testing guide with scenarios, see TESTING_GUIDE.md


πŸ“Š Database Schema

Products Table

CREATE TABLE ProductEntity (
    id INTEGER PRIMARY KEY,
    title TEXT NOT NULL,
    description TEXT,
    userId TEXT NOT NULL,
    createdAt TEXT NOT NULL,
    updatedAt TEXT NOT NULL,
    isSynced INTEGER NOT NULL,
    lastSyncedAt TEXT
);

Queue Table

CREATE TABLE QueuedOperationEntity (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    operationType TEXT NOT NULL,
    productId INTEGER,
    title TEXT,
    description TEXT,
    userId TEXT NOT NULL,
    createdAt TEXT NOT NULL,
    retryCount INTEGER NOT NULL,
    lastError TEXT,
    status TEXT NOT NULL
);

πŸ› Troubleshooting

Common Issues

1. Database file locked

Solution: Close all instances of the application

2. Network timeout

Solution: Check internet connection or increase timeout in ApiClient.kt

3. Sync fails repeatedly

Solution: Check server status and API credentials
Clear queue: Delete ~/.productsync/productsync.db and restart

4. Build fails

Solution: 
- Run ./gradlew clean
- Check JDK version (must be 17+)
- Delete .gradle folder and rebuild

πŸ”§ For detailed troubleshooting, see SETUP_GUIDE.md#troubleshooting


πŸ“ API Documentation

Refer to PRODUCTS_API.md for complete API documentation.

Quick Reference

Endpoint Method Description
/products/:userId GET Get all products
/products/:userId/:id GET Get product by ID
/products/:userId POST Create product
/products/:userId/:id PUT Update product
/products/:userId/:id DELETE Delete product

πŸ”Œ For complete API documentation, see PRODUCTS_API.md


πŸ“„ License

This project is created for technical assessment purposes.


πŸ“ž Support

For questions or issues:

Need Help?

Question Type Resource
How to install? SETUP_GUIDE.md
How does it work? ARCHITECTURE.md
How to test? TESTING_GUIDE.md
API endpoints? PRODUCTS_API.md
Project overview? PROJECT_SUMMARY.md
Build issues? SETUP_GUIDE.md#troubleshooting

πŸ™ Acknowledgments

  • Kotlin Multiplatform Team
  • Compose Multiplatform Community
  • SQLDelight Contributors
  • Ktor Framework Team

Made with ❀️ using Kotlin Multiplatform


πŸ“š Additional Resources

External Documentation

Project Documentation (Internal)


πŸš€ Ready to start? Go to SETUP_GUIDE.md

About

For technical test purpose only

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages