Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ios-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: iOS CI for SPAR

on:
push:
branches: [ SPAR_iOS_App ]
branches: [ SPAR_iOS_App, main ]
pull_request:
branches: [ SPAR_iOS_App ]
branches: [ SPAR_iOS_App, main ]

jobs:
build-and-test:
Expand Down
159 changes: 158 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,158 @@
# MSCS_Spring2025_Capping
# 🖥️ System Processes and Analysis Reporting (S.P.A.R)

**S.P.A.R** is a cross-platform system monitoring application for Ubuntu Linux that provides real-time insights into CPU, memory, disk usage, and running processes. It supports both desktop and mobile platforms, enabling users to track system health anytime, anywhere.

---

## 📦 Components

### 🔹 Desktop App (Electron + React)
- View real-time system metrics
- Responsive UI with Tailwind CSS
- Builds for `.exe`, `.deb`, `.tar.gz`

### 🔹 iOS App (SwiftUI)
- Monitors system metrics
- Supports accessibility: VoiceOver, Dynamic Type
- Face ID integration (Keychain)
- Interaction logging for future analytics

### 🔹 Backend Services
- RESTful API with **Spring Boot**
- Metrics collected using **Node.js** (`systeminformation`, `ps-list`)
- MySQL used for data storage
- API exposes CPU, memory, disk, battery, processes

---

## 🧰 Tech Stack

| Layer | Technology |
|--------------|---------------------------------|
| Desktop UI | Electron, React, Tailwind CSS |
| Mobile App | SwiftUI, Combine, Swift 5 |
| Backend API | Spring Boot (Java), Node.js |
| Data Storage | MySQL |
| Metrics Lib | `systeminformation`, `ps-list` |
| Tools | Xcode 15, IntelliJ, VS Code |

---

## 🚀 Getting Started

### 📁 Clone Repo
```bash
git clone https://github.com/MSCS-Capping/MSCS_Spring2025_Capping.git
cd MSCS_Spring2025_Capping
```

### 🖥️ Desktop App
```bash
cd desktop-app
npm install
npm start # Dev mode
npm run package # Build installer
```

### 📱 iOS App
1. cd SPAR_iOS
2. cd SPAR
1. Open `spar.xcodeproj` in Xcode 15
2. Run on simulator or device
3. View process metrics and test accessibility + logging features

### 🔧 Backend API
```bash
cd backend-api
./mvnw spring-boot:run
```

### 🟡 Node Metrics Collector
```bash
cd node-metrics
npm install
node collector.js
```

Ensure Spring Boot API is running before starting the Electron app.

---

## 🔄 Actions & Deployment

### ✅ GitHub Actions

- iOS app uses GitHub Actions to ensure **all unit and UI tests pass before any merge** into `main`
- CI workflow runs on macOS runners with Xcode configured
- Prevents broken code from being merged into production

```yaml
# .github/workflows/ios-tests.yml
name: iOS Tests
on: [pull_request]
jobs:
test:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Set up Xcode
run: xcodebuild -project iOSApp.xcodeproj -scheme iOSApp -destination 'platform=iOS Simulator,name=iPhone 14' test
```

### 🚀 Render Deployment

- Spring Boot backend is deployed using **Render**
- MySQL database also hosted via Render's managed database services
- Auto-deploy enabled from `main` branch
- Environment variables (DB credentials, API keys) are stored securely in Render's dashboard

---

## 🔐 Security & Testing

- ✅ Unit & Integration Tests for backend and frontend
- ♿ Accessibility tested with VoiceOver and Dynamic Type
- 🔒 Keychain integration for login credentials (iOS)
- 🔄 MySQL data backups and error recovery mechanisms

---

## 🌱 Future Enhancements

- Export reports (CSV, PDF)
- Android version
- Push Notification
- Chatbot

---

## 👥 Contributors

- **Abhijeet Cherungottil**
📧 [[email protected]](mailto:[email protected])

- **Sumanth Kumar Katapally**
📧 [[email protected]](mailto:[email protected])

- **Arjun Suresh (AJ)**
📧 [[email protected]](mailto:[email protected])

---

## 🎥 Demo Video

📽️ Watch it here: Coming Soon
[]()

---

## 📚 References

- [Electron Documentation](https://www.electronjs.org/docs/latest)
- [Spring Boot](https://spring.io/projects/spring-boot)
- [System Information (NPM)](https://www.npmjs.com/package/systeminformation)
- [SwiftUI Accessibility Guide](https://developer.apple.com/documentation/swiftui/accessibility)
- [Tailwind CSS](https://tailwindcss.com/)
- [Render Deployment Docs](https://render.com/docs/deploy-a-java-spring-boot-app)

---
80 changes: 42 additions & 38 deletions SPAR_iOS/SPAR/SPAR.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
3D5995152DB4167A00E9215B /* MemoryUsage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D5995062DB4112100E9215B /* MemoryUsage.swift */; };
3D5995162DB41E0D00E9215B /* MockNetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D59950A2DB4137E00E9215B /* MockNetworkService.swift */; };
3D5995172DB41E1500E9215B /* MockData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D59950D2DB413C100E9215B /* MockData.swift */; };
3D63FB0A2DC4F4F2006F53DE /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D63FB092DC4F4F2006F53DE /* LoadingView.swift */; };
3D78BB2A2DB550E5000E5C2F /* LoginViewUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D78BB292DB550E5000E5C2F /* LoginViewUITests.swift */; };
3D8423A72DB14F86009CF847 /* SPARTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D8423A62DB14F86009CF847 /* SPARTests.swift */; };
3D8423B02DB15044009CF847 /* LaunchTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D8423AF2DB15044009CF847 /* LaunchTest.swift */; };
Expand Down Expand Up @@ -130,6 +131,7 @@
3D59950A2DB4137E00E9215B /* MockNetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockNetworkService.swift; sourceTree = "<group>"; };
3D59950D2DB413C100E9215B /* MockData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockData.swift; sourceTree = "<group>"; };
3D59950F2DB413E300E9215B /* NetworkManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManagerTests.swift; sourceTree = "<group>"; };
3D63FB092DC4F4F2006F53DE /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = "<group>"; };
3D78BB292DB550E5000E5C2F /* LoginViewUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewUITests.swift; sourceTree = "<group>"; };
3D8423A42DB14F86009CF847 /* SPARTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SPARTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3D8423A62DB14F86009CF847 /* SPARTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPARTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -171,30 +173,32 @@
3D07B5312D851C1D0085B32C /* Extensions */ = {
isa = PBXGroup;
children = (
3DCE45902D68C7E700FACBB8 /* View+Extension.swift */,
3DCE458C2D68C1A900FACBB8 /* Logger+Extension.swift */,
3D07B53D2D8887F30085B32C /* ContentSizeCategory+Extension.swift */,
3DCE458C2D68C1A900FACBB8 /* Logger+Extension.swift */,
3D505B742DBACEBF00510486 /* String+Extension.swift */,
3DCE45902D68C7E700FACBB8 /* View+Extension.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
3D07B5322D851C490085B32C /* Onboarding */ = {
isa = PBXGroup;
children = (
3DCE458E2D68C1B200FACBB8 /* OnboardingView.swift */,
3DF9BA522D67767D00D0CC62 /* OnBoardingScreenView.swift */,
3DCE458E2D68C1B200FACBB8 /* OnboardingView.swift */,
);
path = Onboarding;
sourceTree = "<group>";
};
3D07B5332D851C640085B32C /* Utilities */ = {
isa = PBXGroup;
children = (
3DCE45882D68C19200FACBB8 /* Constant.swift */,
3D505B4E2DB9C6AD00510486 /* NavigationButton.swift */,
3D505B5C2DBA657B00510486 /* AppSettings.swift */,
3DCE45882D68C19200FACBB8 /* Constant.swift */,
3D505B782DBB170700510486 /* InfoRow.swift */,
3D63FB092DC4F4F2006F53DE /* LoadingView.swift */,
3DA1AA462DBF034200678160 /* KeychainHelper.swift */,
3D505B4E2DB9C6AD00510486 /* NavigationButton.swift */,
);
path = Utilities;
sourceTree = "<group>";
Expand All @@ -210,57 +214,56 @@
3D07B5352D85C3860085B32C /* ViewModel */ = {
isa = PBXGroup;
children = (
3D505B562DB9DF3F00510486 /* BatteryViewModel.swift */,
3D07B5392D85C3EC0085B32C /* ChartDataContainer.swift */,
3D505B6A2DBAC5EC00510486 /* CpuUsageViewModel.swift */,
3D505B702DBACDE500510486 /* DiskIOViewModel.swift */,
3D505B642DBAAE4D00510486 /* DiskUsageViewModel.swift */,
3D5994F92DB307B400E9215B /* HomeViewModel.swift */,
3D5994FB2DB30B0100E9215B /* LoginViewModel.swift */,
3D505B562DB9DF3F00510486 /* BatteryViewModel.swift */,
3D505B582DB9E14700510486 /* MemoryUsageViewModel.swift */,
3D505B5A2DB9E3F700510486 /* ProcessViewModel.swift */,
3D505B642DBAAE4D00510486 /* DiskUsageViewModel.swift */,
3D505B6A2DBAC5EC00510486 /* CpuUsageViewModel.swift */,
3D505B702DBACDE500510486 /* DiskIOViewModel.swift */,
3DA1AA462DBF034200678160 /* KeychainHelper.swift */,
);
path = ViewModel;
sourceTree = "<group>";
};
3D07B5362D85C3910085B32C /* Data */ = {
isa = PBXGroup;
children = (
3D59950D2DB413C100E9215B /* MockData.swift */,
3D07B5372D85C3BB0085B32C /* ChartData.swift */,
3D07B53F2D88881D0085B32C /* Onboarding.swift */,
3D5995002DB410BD00E9215B /* DeviceSpecification.swift */,
3D5995022DB410DB00E9215B /* ProcessStatus.swift */,
3D5995042DB4110700E9215B /* BatteryInfo.swift */,
3D5995062DB4112100E9215B /* MemoryUsage.swift */,
3D505B5E2DBA94B200510486 /* LoginModel.swift */,
3D505B622DBAAE2C00510486 /* DiskUsage.swift */,
3D07B5372D85C3BB0085B32C /* ChartData.swift */,
3D505B682DBAB31D00510486 /* CPUUsage.swift */,
3D5995002DB410BD00E9215B /* DeviceSpecification.swift */,
3D505B6E2DBACDCA00510486 /* DiskIOModel.swift */,
3D505B622DBAAE2C00510486 /* DiskUsage.swift */,
3D505B5E2DBA94B200510486 /* LoginModel.swift */,
3D5995062DB4112100E9215B /* MemoryUsage.swift */,
3D59950D2DB413C100E9215B /* MockData.swift */,
3D07B53F2D88881D0085B32C /* Onboarding.swift */,
3D5995022DB410DB00E9215B /* ProcessStatus.swift */,
);
path = Data;
sourceTree = "<group>";
};
3D505B4B2DB9C19000510486 /* Device */ = {
isa = PBXGroup;
children = (
3D505B4C2DB9C1BE00510486 /* DeviceOptions.swift */,
3D505B502DB9D76200510486 /* BatteryDetailView.swift */,
3D505B522DB9DAA500510486 /* MemoryUsageDetailView.swift */,
3D505B542DB9DD5500510486 /* ProcessDetailPage.swift */,
3D505B662DBAAFFE00510486 /* DiskUsageDetailView.swift */,
3D505B6C2DBAC6EA00510486 /* CpuUsageDetailView.swift */,
3D505B4C2DB9C1BE00510486 /* DeviceOptions.swift */,
3D505B722DBACE3800510486 /* DiskIODetailView.swift */,
3D505B662DBAAFFE00510486 /* DiskUsageDetailView.swift */,
3D505B522DB9DAA500510486 /* MemoryUsageDetailView.swift */,
3D505B542DB9DD5500510486 /* ProcessDetailPage.swift */,
);
path = Device;
sourceTree = "<group>";
};
3D5994F12DB2ACB300E9215B /* Login */ = {
isa = PBXGroup;
children = (
3D5994F22DB2B79400E9215B /* LoginView.swift */,
3D5994F42DB2BA1200E9215B /* BackgroundAnimationView.swift */,
3D5994F22DB2B79400E9215B /* LoginView.swift */,
);
path = Login;
sourceTree = "<group>";
Expand All @@ -269,33 +272,33 @@
isa = PBXGroup;
children = (
3D59950A2DB4137E00E9215B /* MockNetworkService.swift */,
3D5994FE2DB3FFBE00E9215B /* NetworkService.swift */,
3D5995082DB4114200E9215B /* NetworkManager.swift */,
3D5994FE2DB3FFBE00E9215B /* NetworkService.swift */,
);
path = NetworkService;
sourceTree = "<group>";
};
3D63FB062DC1B4FA006F53DE /* View */ = {
isa = PBXGroup;
children = (
3DF9BA502D67762C00D0CC62 /* HomeView.swift */,
3DCE458A2D68C19F00FACBB8 /* SplashScreenView.swift */,
3D07B5322D851C490085B32C /* Onboarding */,
3D07B5342D85C3740085B32C /* ChartUI */,
3D5994F12DB2ACB300E9215B /* Login */,
3D505B4B2DB9C19000510486 /* Device */,
3DF9BA502D67762C00D0CC62 /* HomeView.swift */,
3D5994F12DB2ACB300E9215B /* Login */,
3D07B5322D851C490085B32C /* Onboarding */,
3DCE458A2D68C19F00FACBB8 /* SplashScreenView.swift */,
);
path = View;
sourceTree = "<group>";
};
3D8423A52DB14F86009CF847 /* SPARTests */ = {
isa = PBXGroup;
children = (
3D8423A62DB14F86009CF847 /* SPARTests.swift */,
3D8423AF2DB15044009CF847 /* LaunchTest.swift */,
3D8423B22DB15082009CF847 /* OnboardingTests.swift */,
3D59950F2DB413E300E9215B /* NetworkManagerTests.swift */,
3D78BB292DB550E5000E5C2F /* LoginViewUITests.swift */,
3D59950F2DB413E300E9215B /* NetworkManagerTests.swift */,
3D8423B22DB15082009CF847 /* OnboardingTests.swift */,
3D8423A62DB14F86009CF847 /* SPARTests.swift */,
);
path = SPARTests;
sourceTree = "<group>";
Expand All @@ -321,16 +324,16 @@
3D98C7F02D4FE04500462EF4 /* SPAR */ = {
isa = PBXGroup;
children = (
3D63FB062DC1B4FA006F53DE /* View */,
3D5994FD2DB3FF0700E9215B /* NetworkService */,
3D98C7F52D4FE04700462EF4 /* Assets.xcassets */,
3D98C7F32D4FE04500462EF4 /* ContentView.swift */,
3D07B5362D85C3910085B32C /* Data */,
3D07B5352D85C3860085B32C /* ViewModel */,
3D07B5332D851C640085B32C /* Utilities */,
3D07B5312D851C1D0085B32C /* Extensions */,
3D98C7F12D4FE04500462EF4 /* SPARApp.swift */,
3D98C7F32D4FE04500462EF4 /* ContentView.swift */,
3D98C7F52D4FE04700462EF4 /* Assets.xcassets */,
3D5994FD2DB3FF0700E9215B /* NetworkService */,
3D98C7F72D4FE04700462EF4 /* Preview Content */,
3D98C7F12D4FE04500462EF4 /* SPARApp.swift */,
3D07B5332D851C640085B32C /* Utilities */,
3D63FB062DC1B4FA006F53DE /* View */,
3D07B5352D85C3860085B32C /* ViewModel */,
);
path = SPAR;
sourceTree = "<group>";
Expand Down Expand Up @@ -513,6 +516,7 @@
3D07B53A2D85C3EC0085B32C /* ChartDataContainer.swift in Sources */,
3D07B5402D88881D0085B32C /* Onboarding.swift in Sources */,
3D5994F52DB2BA1200E9215B /* BackgroundAnimationView.swift in Sources */,
3D63FB0A2DC4F4F2006F53DE /* LoadingView.swift in Sources */,
3D505B572DB9DF3F00510486 /* BatteryViewModel.swift in Sources */,
3DCE45892D68C19200FACBB8 /* Constant.swift in Sources */,
3D5994F32DB2B79400E9215B /* LoginView.swift in Sources */,
Expand Down
Loading
Loading