Skip to content

Commit 2084b9a

Browse files
committed
Initial commit
0 parents  commit 2084b9a

248 files changed

Lines changed: 30483 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Backend Deploy
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'backend/**'
9+
10+
jobs:
11+
test:
12+
runs-on: ubuntu-latest
13+
env:
14+
CI: true
15+
services:
16+
mongodb:
17+
image: mongo:7
18+
ports:
19+
- 27017:27017
20+
defaults:
21+
run:
22+
working-directory: backend
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- name: Set up JDK 21
27+
uses: actions/setup-java@v4
28+
with:
29+
java-version: '21'
30+
distribution: 'temurin'
31+
32+
- name: Cache Maven packages
33+
uses: actions/cache@v4
34+
with:
35+
path: ~/.m2
36+
key: ${{ runner.os }}-maven-${{ hashFiles('backend/pom.xml') }}
37+
38+
- name: Build and Test
39+
run: mvn clean verify -e
40+
env:
41+
SPRING_PROFILES_ACTIVE: test
42+
43+
deploy:
44+
needs: test
45+
runs-on: ubuntu-latest
46+
steps:
47+
- uses: actions/checkout@v4
48+
49+
- name: Authenticate to Google Cloud
50+
uses: google-github-actions/auth@v2
51+
with:
52+
credentials_json: ${{ secrets.GCP_SA_KEY }}
53+
54+
- name: Set up Cloud SDK
55+
uses: google-github-actions/setup-gcloud@v2
56+
57+
- name: Build and Push Docker Image
58+
run: |
59+
gcloud builds submit \
60+
--tag northamerica-northeast2-docker.pkg.dev/gen-lang-client-0316039122/ontrack-repo/ontrack-backend \
61+
./backend
62+
63+
- name: Deploy to Cloud Run
64+
run: |
65+
gcloud run deploy ontrack-backend \
66+
--image=northamerica-northeast2-docker.pkg.dev/gen-lang-client-0316039122/ontrack-repo/ontrack-backend \
67+
--region=northamerica-northeast2 \
68+
--platform=managed \
69+
--allow-unauthenticated \
70+
--port=8080
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Backend SonarCloud Analysis
2+
on:
3+
push:
4+
paths:
5+
- 'backend/**'
6+
pull_request:
7+
paths:
8+
- 'backend/**'
9+
jobs:
10+
sonar:
11+
runs-on: ubuntu-latest
12+
env:
13+
CI: true
14+
services:
15+
mongodb:
16+
image: mongo:7
17+
ports:
18+
- 27017:27017
19+
20+
defaults:
21+
run:
22+
working-directory: backend
23+
24+
steps:
25+
- uses: actions/checkout@v4
26+
with:
27+
fetch-depth: 0
28+
29+
- name: Set up JDK 21
30+
uses: actions/setup-java@v4
31+
with:
32+
java-version: '21'
33+
distribution: 'temurin'
34+
35+
- name: Cache Maven packages
36+
uses: actions/cache@v4
37+
with:
38+
path: ~/.m2
39+
key: ${{ runner.os }}-maven-${{ hashFiles('backend/pom.xml') }}
40+
41+
- name: Build and Test
42+
run: mvn clean verify -e
43+
env:
44+
SPRING_PROFILES_ACTIVE: test
45+
46+
- name: SonarCloud Scan
47+
uses: SonarSource/sonarqube-scan-action@v5
48+
with:
49+
projectBaseDir: backend
50+
env:
51+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Frontend Deploy
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'frontend/**'
9+
10+
jobs:
11+
deploy:
12+
runs-on: ubuntu-latest
13+
14+
defaults:
15+
run:
16+
working-directory: frontend
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Set up Node
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: '20'
25+
26+
- name: Install dependencies
27+
run: npm install
28+
29+
- name: Build Expo Web
30+
run: npm run build:web
31+
32+
- name: Deploy to Firebase Hosting
33+
uses: FirebaseExtended/action-hosting-deploy@v0
34+
with:
35+
repoToken: ${{ secrets.GITHUB_TOKEN }}
36+
firebaseServiceAccount: ${{ secrets.GCP_SA_KEY }}
37+
channelId: live
38+
projectId: gen-lang-client-0316039122
39+
entryPoint: frontend
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Frontend SonarCloud Analysis
2+
on:
3+
push:
4+
paths:
5+
- 'frontend/**'
6+
pull_request:
7+
paths:
8+
- 'frontend/**'
9+
jobs:
10+
sonar:
11+
runs-on: ubuntu-latest
12+
defaults:
13+
run:
14+
working-directory: frontend
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Set up Node
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: '20'
24+
25+
- name: Install dependencies
26+
run: npm install
27+
28+
- name: SonarCloud Scan
29+
uses: SonarSource/sonarqube-scan-action@v5
30+
with:
31+
projectBaseDir: frontend
32+
env:
33+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea/
2+
target/
3+
.env

‎README.md‎

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<p align="center">
2+
<img src="https://img.shields.io/badge/Spring%20Boot-3.5-6DB33F?logo=springboot&logoColor=white" alt="Spring Boot" />
3+
<img src="https://img.shields.io/badge/Java-21-ED8B00?logo=openjdk&logoColor=white" alt="Java" />
4+
<img src="https://img.shields.io/badge/Expo-SDK%2054-000020?logo=expo&logoColor=white" alt="Expo" />
5+
<img src="https://img.shields.io/badge/React%20Native-0.81-61DAFB?logo=react&logoColor=white" alt="React Native" />
6+
<img src="https://img.shields.io/badge/Firebase-Hosting-FFCA28?logo=firebase&logoColor=black" alt="Firebase" />
7+
<img src="https://img.shields.io/badge/Google%20Cloud-Run-4285F4?logo=googlecloud&logoColor=white" alt="Cloud Run" />
8+
</p>
9+
10+
# onTrack
11+
12+
**onTrack** is an academic progress tracker built for McMaster University students. Upload your transcript, track your GPA, manage course assessments, and sync deadlines to Google Calendar — all in one place.
13+
14+
> **Live at [ontrackmac.ca](https://ontrackmac.ca)**
15+
16+
---
17+
18+
## Features
19+
20+
### Transcript Upload
21+
Upload your McMaster transcript as a PDF and onTrack automatically parses it to import your past courses, grades, and current term enrollments. Supports multi-year courses (e.g., `ENGINEER 1P13 A/B`) and handles duplicate detection.
22+
23+
### GPA Tracking
24+
View your cumulative GPA on both the **4.0** and **12.0** scales. Set a target GPA and visualize your progress. GPA is recalculated automatically whenever courses or grades change.
25+
26+
### AI-Powered Syllabus Extraction
27+
Upload a course syllabus PDF and onTrack uses **Google Gemini 2.5 Pro** to extract the full assessment breakdown — names, weights, due dates, and grading schemes. Supports courses with multiple grading schemes and selection rules (e.g., "best of" schemes). Extraction runs asynchronously with real-time job status polling.
28+
29+
### Assessment Table
30+
View and edit assessment details for each course: weights, due dates, times, locations, and grades. Tables are automatically populated from uploaded syllabi or can be built manually.
31+
32+
### Course Grade Calculator
33+
Enter grades for individual assessments and see your projected final course grade, calculated from syllabus weight breakdowns across all applicable grading schemes.
34+
35+
### Google Calendar Sync
36+
Connect your Google account and export upcoming assessment deadlines to Google Calendar. Uses a **diff-based sync algorithm** — re-syncing only adds new events and removes outdated ones, never creating duplicates.
37+
38+
### Dashboard
39+
An at-a-glance overview of your current GPA vs. target, upcoming deadlines, and active courses. Quick actions to add assignments, sync your calendar, or report a bug.
40+
41+
### Course Search
42+
Browse McMaster's course catalogue to look up course details and descriptions.
43+
44+
### My Courses
45+
Manage your current term courses, upload syllabi, and access per-course assessment tables.
46+
47+
---
48+
49+
## Security
50+
51+
Protecting student data is a priority. Here's how onTrack handles security:
52+
53+
| Measure | Details |
54+
|---------|---------|
55+
| **Authentication** | Stateless JWT (HMAC-SHA, 1-hour expiry). No server-side sessions. |
56+
| **Password Storage** | BCrypt with strength factor 12. Passwords are never stored in plaintext. |
57+
| **Password Requirements** | Minimum 8 characters with at least one uppercase letter, one lowercase letter, and one digit. |
58+
| **Grade Encryption** | All grade data is encrypted at rest using **AES-256-GCM** with per-record initialization vectors. |
59+
| **Email Verification** | Token-based verification required before account activation. Tokens are cryptographically random (32 bytes) with a 15-minute expiry and single-use enforcement. |
60+
| **Rate Limiting** | Sliding-window rate limiter on all endpoints — 10 req/min on authentication routes, 60 req/min on general routes. |
61+
| **OAuth 2.0** | Google Calendar integration uses JWT-signed state tokens (5-minute expiry) to prevent CSRF during the OAuth flow. |
62+
| **Input Validation** | Server-side validation on all user inputs with a global exception handler that returns structured error responses. |
63+
| **Error Handling** | Stack traces, exception types, and internal error messages are never exposed to clients. |
64+
| **McMaster-Only Registration** | Only `@mcmaster.ca` email addresses can register. |
65+
| **CORS** | Restricted to configured frontend origin with credentials support. |
66+
| **Infrastructure** | Hosted on Google Cloud (northamerica-northeast2) with Cloud SQL (PostgreSQL) and MongoDB Atlas. Backend deployed via Cloud Run with containerized builds. |
67+
68+
---
69+
70+
## Tech Stack
71+
72+
| Layer | Technology |
73+
|-------|-----------|
74+
| **Frontend** | React Native, Expo SDK 54, expo-router, react-native-reanimated |
75+
| **Web Hosting** | Firebase Hosting |
76+
| **Backend** | Spring Boot 3.5, Java 21 |
77+
| **Databases** | PostgreSQL (Google Cloud SQL), MongoDB Atlas |
78+
| **AI** | Google Gemini 2.5 Pro |
79+
| **Auth** | JWT + BCrypt + email verification |
80+
| **Email** | Resend |
81+
| **CI/CD** | GitHub Actions |
82+
| **Infrastructure** | Google Cloud Run, Firebase Hosting |
83+
84+
---
85+
86+
## Project Structure
87+
88+
```
89+
onTrack/
90+
├── backend/ # Spring Boot REST API
91+
│ └── src/main/java/.../
92+
│ ├── accounts/ # Student profiles, transcript upload, course management
93+
│ ├── assessmenttable/ # Assessment table CRUD and syllabus integration
94+
│ ├── calendar/ # Google Calendar OAuth and diff-based sync
95+
│ ├── courses/ # Course catalogue search
96+
│ ├── mailing/ # Email verification and password reset emails
97+
│ ├── security/ # JWT auth, rate limiting, encryption, user management
98+
│ └── syllabus/ # Syllabus upload, Gemini AI extraction, grading schemes
99+
├── frontend/ # Expo React Native app
100+
│ ├── app/ # expo-router routes
101+
│ ├── screens/ # Screen components
102+
│ ├── src/ # Theme, config, utilities
103+
│ └── public/ # Landing page, privacy policy
104+
└── .github/workflows/ # CI/CD pipelines
105+
```
106+
107+
---
108+
109+
## Deployment
110+
111+
| Component | Pipeline | Target |
112+
|-----------|----------|--------|
113+
| **Backend** | Push to `main` (backend changes) | Docker build → Google Cloud Run |
114+
| **Frontend** | Push to `main` (frontend changes) | Expo web export → Firebase Hosting |
115+
116+
Both pipelines run automatically via GitHub Actions. All secrets are stored in GitHub Secrets — no credentials are committed to the repository.
117+
118+
---
119+
120+
## Acknowledgements
121+
122+
- [macgrades/transcript-api](https://github.com/macgrades/transcript-api) — McMaster transcript parsing API that inspired the transcript upload feature.

‎backend/.gitattributes‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/mvnw text eol=lf
2+
*.cmd text eol=crlf

‎backend/.gitignore‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
HELP.md
2+
target/
3+
.mvn/wrapper/maven-wrapper.jar
4+
!**/src/main/**/target/
5+
!**/src/test/**/target/
6+
7+
### STS ###
8+
.apt_generated
9+
.classpath
10+
.factorypath
11+
.project
12+
.settings
13+
.springBeans
14+
.sts4-cache
15+
16+
### IntelliJ IDEA ###
17+
.idea
18+
*.iws
19+
*.iml
20+
*.ipr
21+
22+
### NetBeans ###
23+
/nbproject/private/
24+
/nbbuild/
25+
/dist/
26+
/nbdist/
27+
/.nb-gradle/
28+
build/
29+
!**/src/main/**/build/
30+
!**/src/test/**/build/
31+
32+
### VS Code ###
33+
.vscode/
34+
35+
### Environment ###
36+
.env
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
wrapperVersion=3.3.2
18+
distributionType=only-script
19+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip

‎backend/Dockerfile‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM eclipse-temurin:21-jdk-alpine AS build
2+
WORKDIR /app
3+
COPY pom.xml .
4+
COPY src ./src
5+
RUN apk add --no-cache maven && mvn clean package -DskipTests
6+
7+
FROM eclipse-temurin:21-jre-alpine
8+
WORKDIR /app
9+
COPY --from=build /app/target/*.jar app.jar
10+
EXPOSE 8080
11+
ENTRYPOINT ["java", "-jar", "app.jar"]

0 commit comments

Comments
 (0)