Track applications, set reminders, store resumes, and access your data seamlessly with Google Drive integration.
JobTrackr is a modern, intuitive job tracking tool designed to streamline your job application process. Built with job seekers in mind, it helps you stay organized, efficient, and productive throughout your job search journey.
| Node.js (v14 or higher) | |
| npm/yarn | |
| Git | |
| Firebase account | |
| Google Cloud account | |
| AWS account |
# Clone the repository
git clone https://github.com/phantombeast7/JobTrackr.git
cd JobTrackr
# Install dependencies
npm install🔥 Click to expand Firebase setup instructions
- Visit Firebase Console
- Create new project
- Navigate to Project Settings
const firebaseConfig = {
apiKey: YOUR_API_KEY,
authDomain: YOUR_AUTH_DOMAIN,
projectId: YOUR_PROJECT_ID,
storageBucket: YOUR_STORAGE_BUCKET,
messagingSenderId: YOUR_MESSAGING_SENDER_ID,
appId: YOUR_APP_ID,
measurementId: YOUR_MEASUREMENT_ID
};Create .env.local:
NEXT_PUBLIC_FIREBASE_API_KEY=YOUR_API_KEY
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=YOUR_AUTH_DOMAIN
NEXT_PUBLIC_FIREBASE_PROJECT_ID=YOUR_PROJECT_ID
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=YOUR_STORAGE_BUCKET
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=YOUR_MESSAGING_SENDER_ID
NEXT_PUBLIC_FIREBASE_APP_ID=YOUR_APP_ID
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=YOUR_MEASUREMENT_ID
FIREBASE_PROJECT_ID=YOUR_PROJECT_ID
FIREBASE_CLIENT_EMAIL=YOUR_CLIENT_EMAIL
FIREBASE_PRIVATE_KEY=YOUR_PRIVATE_KEYrules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Helper functions
function isSignedIn() {
return request.auth != null;
}
function isOwner(userId) {
return request.auth.uid == userId;
}
function isValidApplication() {
let data = request.resource.data;
return data.userId == request.auth.uid &&
data.companyName is string &&
data.jobTitle is string &&
data.status in ['Applied', 'Interviewing', 'Offered', 'Rejected'] &&
data.applicationDate is string;
}
function isValidReminder() {
let data = request.resource.data;
return data.userId == request.auth.uid &&
data.type in ['interview', 'followup'] &&
data.date is string &&
data.message is string;
}
// Users collection
match /users/{userId} {
allow read, write: if isSignedIn() && isOwner(userId);
// Allow reading user settings
match /settings/{settingId} {
allow read: if isSignedIn() && isOwner(userId);
allow write: if isSignedIn() && isOwner(userId);
}
}
// Applications collection
match /applications/{applicationId} {
// Allow read operations
allow list: if isSignedIn();
allow get: if isSignedIn() && resource.data.userId == request.auth.uid;
// Allow create with validation
allow create: if isSignedIn() && isValidApplication();
// Allow update and delete for document owner
allow update: if isSignedIn() &&
resource.data.userId == request.auth.uid &&
isValidApplication();
allow delete: if isSignedIn() && resource.data.userId == request.auth.uid;
}
// Reminders collection
match /reminders/{reminderId} {
allow read: if isSignedIn() &&
(resource == null || resource.data.userId == request.auth.uid);
allow create: if isSignedIn() && isValidReminder();
allow update, delete: if isSignedIn() &&
resource.data.userId == request.auth.uid;
}
// Blacklisted Companies collection
match /blacklistedCompanies/{companyId} {
// Anyone signed in can read blacklisted companies
allow read: if isSignedIn();
// Blacklisted Companies collection
// Users can create reports
allow create: if isSignedIn() &&
request.resource.data.reportedBy == request.auth.uid &&
request.resource.data.companyName is string &&
request.resource.data.reason is string;
// Only the reporter can update their report
allow update: if isSignedIn() &&
resource.data.reportedBy == request.auth.uid &&
resource.data.status == 'pending';
// Allow delete for the reporter
allow delete: if isSignedIn() && resource.data.reportedBy == request.auth.uid;
}
// Default rule - deny everything else
match /{document=**} {
allow read, write: if false;
}
// Reminders collection
match /reminders/{reminderId} {
allow read: if request.auth != null &&
resource.data.userId == request.auth.uid;
allow create: if request.auth != null &&
request.resource.data.userId == request.auth.uid;
allow update: if request.auth != null &&
resource.data.userId == request.auth.uid;
allow delete: if request.auth != null &&
resource.data.userId == request.auth.uid;
}
}
}Required indexes:
Collection ID Fields indexed Query scope Status
applications userId Ascending resumeUrl Ascending __name__ Ascending Collection Enabled
applications userId Ascending createdAt Descending __name__ Descending Collection Enabled
reminders sent Ascending userId Ascending scheduledFor Ascending __name__ Ascending Collection Enabled
reminders userId Ascending scheduledFor Descending __name__ Descending Collection Enabled📁 Click to expand Google Drive setup instructions
- Visit Google Cloud Console
- Enable Google Drive API
- Create OAuth 2.0 credentials
- Configure redirect URIs:
# Local
http://localhost:3000
http://localhost:3000/api/auth/google-drive/callback
# Production
https://jobtrackr7.netlify.app/
https://jobtrackr7.netlify.app/api/auth/google-drive/callback- Add to
.env.local:
NEXT_PUBLIC_GOOGLE_DRIVE_CLIENT_ID=YOUR_GOOGLE_DRIVE_CLIENT_ID
GOOGLE_DRIVE_CLIENT_SECRET=YOUR_GOOGLE_DRIVE_CLIENT_SECRET
NEXT_PUBLIC_GOOGLE_DRIVE_REDIRECT_URI=http://localhost:3000/api/auth/google-drive/callback📧 Click to expand AWS SES setup instructions
- Access AWS Console
- Configure SES:
- Create Email Identity
- Set up SMTP credentials
- Add to
.env.local:
AWS_SES_SMTP_HOST=YOUR_SMTP_HOST
AWS_SES_SMTP_PORT=YOUR_SMTP_PORT
AWS_SES_USER=YOUR_SMTP_USER
AWS_SES_PASSWORD=YOUR_SMTP_PASSWORD
AWS_SES_FROM_EMAIL=YOUR_VERIFIED_EMAILWe love contributions! Here's how you can help:
- 🍴 Fork the repository
- 🌿 Create your feature branch
- ✍️ Commit your changes
- 🚀 Push to the branch
- 🎉 Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.








