CREST is a mobile platform built for Bonifacio D. Borebor Sr. High School that gives educators and students centralized access to compiled research papers and educational documents. It streamlines how academic resources are organized, discovered, and shared.
Why does this exist? There was no electronic backup for research at our school. CREST makes research easily available to every student, fostering collaborative learning and efficient knowledge sharing.
- CREST
- Google Sign-In — Secure login using institutional or personal Google accounts
- Role-based access — Distinct interfaces and permissions for Students and Teachers
- Students — Browse research, view details, favorite papers, and upload group research for approval
- Teachers — Browse research, upload materials, manage student submissions (approve / deny), and administer accounts
- Centralized repository — Single source of truth for all school research papers
- Structured uploads — PDF upload form with metadata (title, strand, research type, authors)
- Teacher approval workflow — Student uploads enter a "Pending" state until a teacher approves them
- Favorites — Bookmark research papers for quick access
- Search & filter — Find research by title, status (Pending / Accepted), or sort alphabetically
- Integrated PDF viewer — Lazy-loading renderer for smooth scrolling of large documents, directly in-app
- Responsive UI — Optimized for phones and tablets
- Student groups — Organize students into groups for collaborative research uploads
- Group detail views — Manage group membership and track submissions
- Account management — Teachers can view and manage user accounts
- Storage management — Monitor and manage cloud storage usage
CREST follows MVVM + Repository with a single-activity Compose architecture:
┌─────────────────────────────────────────────────────────┐
│ UI Layer │
│ Screens (Compose) ──► ViewModels ──► UI State (Flow) │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ Data Layer │
│ 13 Repository classes │
│ ┌──────────────┬──────────────┬──────────────┐ │
│ │ Firebase │ Appwrite │ Local │ │
│ │ Auth + DB │ Storage │ FileCache / │ │
│ │ (Firestore) │ (Documents) │ UserPrefs │ │
│ └──────────────┴──────────────┴──────────────┘ │
└─────────────────────────────────────────────────────────┘
- Single Activity (
MainActivity) hosts a ComposeNavHostwith 15+ routes - Hilt provides dependency injection across the entire app
- Dual backend — Firebase handles auth & Firestore; Appwrite handles file storage
- Kotlin Coroutines & Flow for reactive, asynchronous data streams
| Category | Technology |
|---|---|
| Language | Kotlin 2.0 |
| UI | Jetpack Compose with Material Design 3 |
| Architecture | MVVM + Repository pattern |
| Navigation | Compose Navigation |
| DI | Hilt (Dagger) |
| Auth | Firebase Authentication (Google Sign-In) |
| Database | Cloud Firestore |
| File Storage | Appwrite SDK for Android |
| Async | Kotlin Coroutines & Flow |
| Local Storage | DataStore Preferences + custom file cache |
| Testing | JUnit 4, MockK, Turbine, Espresso, Compose UI tests |
| Benchmarking | Macrobenchmark |
| Build | Gradle (Kotlin DSL) with version catalog |
CREST/
├── app/
│ └── src/main/java/com/bdbshs/crest/
│ ├── CrestApplication.kt # @HiltAndroidApp — init Firebase, Appwrite
│ ├── MainActivity.kt # Single-activity entry point
│ ├── data/
│ │ ├── AppwriteClient.kt # Appwrite SDK wrapper
│ │ ├── FirebaseClient.kt # Firebase SDK wrapper
│ │ ├── CrestConfig.kt # App configuration constants
│ │ ├── FileCache.kt # Local file caching
│ │ ├── UserPrefs.kt # DataStore preferences
│ │ └── repository/ # 13 repositories (Auth, Research, Groups, …)
│ ├── di/
│ │ └── AppModule.kt # Hilt @Module for app-wide dependencies
│ ├── navigation/
│ │ └── CrestApp.kt # NavHost, routes, navigation actions
│ ├── ui/
│ │ ├── components/ # 8 reusable composables (NavBar, Cards, …)
│ │ ├── screens/ # 18 screens + shared composables
│ │ │ ├── common/ # ActionBottomSheet, EmptyState, Shimmer, …
│ │ │ └── drawer/ # Navigation drawer
│ │ ├── viewmodels/ # 14 ViewModels
│ │ └── theme/ # Material 3 theme (Color, Type, Shapes, …)
│ └── utils/
│ └── FileUtils.kt # File utility helpers
├── benchmark/ # Macrobenchmark module
├── gradle/
│ └── libs.versions.toml # Version catalog
├── build.gradle.kts # Root build file
└── settings.gradle.kts
| Requirement | Version |
|---|---|
| Android Studio | Ladybug (2024.2.1) or newer |
| JDK | 11 |
| Compile SDK | 35 |
| Min SDK | 24 (Android 7.0) |
| Target SDK | 35 |
| Firebase | Auth + Firestore enabled |
| Appwrite | Endpoint, project, and bucket configured |
git clone https://github.com/james719-code/CRESTV2.git
cd CRESTV2- Launch Android Studio
- File > Open — navigate to the cloned folder and click OK
- Wait for Gradle sync to complete (may take a few minutes on first import)
See Configuration below for Firebase, Appwrite, and signing setup.
- Click Sync Project with Gradle Files (elephant icon in the toolbar)
- Build > Make Project to verify everything compiles
Place your google-services.json in the app/ directory.
Download it from the Firebase Console — ensure Authentication and Firestore are enabled in your project.
The app resolves Appwrite values in this order: local.properties → Gradle properties → fallback defaults.
Add to local.properties:
APPWRITE_ENDPOINT=https://fra.cloud.appwrite.io/v1
APPWRITE_PROJECT_ID=your_project_id
APPWRITE_BUCKET_ID=your_bucket_idRelease builds read signing config from environment variables (used by CI / GitHub Actions):
| Variable | Description |
|---|---|
RELEASE_STORE_FILE |
Path to the keystore file |
RELEASE_STORE_PASSWORD |
Keystore password |
RELEASE_KEY_ALIAS |
Key alias |
RELEASE_KEY_PASSWORD |
Key password |
All commands are run from the project root.
| Task | Windows | macOS / Linux |
|---|---|---|
| Debug build | gradlew.bat assembleDebug |
./gradlew assembleDebug |
| Install debug | gradlew.bat installDebug |
./gradlew installDebug |
| Release build | gradlew.bat assembleRelease |
./gradlew assembleRelease |
| Variant | Suffix | Minify | Debuggable | Use Case |
|---|---|---|---|---|
| debug | -dev |
No | Yes | Development & testing |
| release | — | Yes (R8 + resource shrinking) | No | Production deployment |
| benchmark | — | Yes (inherits release) | No | Performance profiling |
# All unit tests
./gradlew testDebugUnitTest
# Specific test class
./gradlew testDebugUnitTest --tests "com.bdbshs.crest.data.FileCacheTest"Windows equivalent
gradlew.bat testDebugUnitTest
gradlew.bat testDebugUnitTest --tests "com.bdbshs.crest.data.FileCacheTest"Requires a connected device or emulator:
# All instrumented tests
./gradlew connectedDebugAndroidTest
# Specific test
./gradlew connectedDebugAndroidTest --tests "com.bdbshs.crest.ui.screens.DocumentsScreenTest"Windows equivalent
gradlew.bat connectedDebugAndroidTest
gradlew.bat connectedDebugAndroidTest --tests "com.bdbshs.crest.ui.screens.DocumentsScreenTest"Requires a physical device (recommended) or API 29+ emulator:
./gradlew :benchmark:connectedBenchmarkAndroidTestResults are saved under benchmark/build/outputs/.
| Test Type | Steps |
|---|---|
| Unit | Navigate to app/src/test/java/ → right-click a class or package → Run Tests |
| Instrumented | Connect a device → navigate to app/src/androidTest/java/ → right-click → Run Tests |
| Benchmark | Open Gradle panel → benchmark > Tasks > verification → run connectedBenchmarkAndroidTest |
| Problem | Solution |
|---|---|
| Gradle sync fails | Check internet connection; try File > Invalidate Caches |
Missing google-services.json |
Download from Firebase Console → place in app/ |
| Appwrite config not applied | Verify APPWRITE_* keys in local.properties or passed as -P Gradle properties |
| Tests not running | Ensure the debug build variant is selected |
| Benchmark crashes | Use a physical device; ensure benchmark variant is selected |
| JDK version mismatch | File > Project Structure > SDK Location → set to JDK 11 |
James Ryan S. Gallego