Smart India Hackathon 2024

August 8, 2024 (4mo ago)


Team Roles

Dev Shakya @devxoshakya

Frontend (Next.js, MagicUI, AceternityUI, Javascript)

Akshita Srivastava @akshitasrivastava20

Frontend (React.js, Javascript)

Ayush Bisht @WebDev-Ayush

Backend (express, Node.js)

Suryansh Patwal @StrugglerSuryansh

Database (MongoDB, Passport.js)

Yagyansh Singh Deshwal @yaggggy

Database (MongoDB)


Comprehensive Guide to Developing a Geolocation-Based Attendance Tracking App

This guide provides a detailed approach to building the attendance tracking app using Next.js, MongoDB, Express, Node.js, Google Maps API, Tailwind CSS, Magic UI, Aceternity UI, and Passport.js for authentication. The app will be developed as a PWA and later converted into a TWA for Android.


1. Project Structure

Here's an overview of the Next.js project structure:

attendance-app/
│
├── public/
│   ├── icons/
│   ├── manifest.json
│   └── service-worker.js
│
├── src/
│   ├── components/
│   │   ├── Auth/
│   │   ├── Dashboard/
│   │   ├── Layout/
│   │   └── Map/
│   │
│   ├── pages/
│   │   ├── api/
│   │   │   ├── auth/
│   │   │   ├── employees/
│   │   │   ├── geolocation/
│   │   │   ├── admin/
│   │   │   └── moderator/
│   │   ├── _app.jsx
│   │   ├── _document.jsx
│   │   └── index.jsx
│   │
│   ├── styles/
│   │   └── globals.css
│   │
│   ├── utils/
│   │   ├── apiHelper.js
│   │   └── geolocationHelper.js
│   │
│   ├── middleware/
│   │   ├── passport.js
│   │   └── authMiddleware.js
│   │
│   ├── config/
│   │   └── db.js
│   │
│   └── models/
│       ├── User.js
│       ├── Admin.js
│       ├── Moderator.js
│       └── Attendance.js
│
├── .babelrc
├── .eslintrc.json
├── package.json
└── tailwind.config.js

2. Tailwind CSS Integration

Global Styles:

Using Tailwind in Components:


3. Database Design and Models

We will use MongoDB with Mongoose as our ODM.

Database Models:

  1. User Model:

    const mongoose = require('mongoose');
     
    const userSchema = new mongoose.Schema({
      name: { type: String, required: true },
      rollNo: { type: String, unique: true, required: true },
      email: { type: String, unique: true, required: true },
      password: { type: String, required: true },
      role: { type: String, enum: ['employee', 'admin', 'moderator'], default: 'employee' },
      location: {
        type: { type: String, default: 'Point' },
        coordinates: [Number],
      },
      createdAt: { type: Date, default: Date.now },
    });
     
    userSchema.index({ location: '2dsphere' });
     
    module.exports = mongoose.model('User', userSchema);
  2. Attendance Model:

    const mongoose = require('mongoose');
     
    const attendanceSchema = new mongoose.Schema({
      user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
      checkIn: { type: Date, required: true },
      checkOut: { type: Date },
      location: {
        type: { type: String, default: 'Point' },
        coordinates: [Number],
      },
    });
     
    module.exports = mongoose.model('Attendance', attendanceSchema);
  3. Admin Model:

    const mongoose = require('mongoose');
     
    const adminSchema = new mongoose.Schema({
      user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
      officeLocation: {
        type: { type: String, default: 'Point' },
        coordinates: [Number],
      },
    });
     
    module.exports = mongoose.model('Admin', adminSchema);
  4. Moderator Model:

    const mongoose = require('mongoose');
     
    const moderatorSchema = new mongoose.Schema({
      user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
    });
     
    module.exports = mongoose.model('Moderator', moderatorSchema);

4. Backend Structure with Passport.js Authentication

Passport.js Configuration

  1. Passport Middleware (passport.js):

    const passport = require('passport');
    const LocalStrategy = require('passport-local').Strategy;
    const User = require('../models/User');
    const bcrypt = require('bcrypt');
     
    passport.use(new LocalStrategy({
      usernameField: 'email'
    }, async (email, password, done) => {
      try {
        const user = await User.findOne({ email });
        if (!user) return done(null, false, { message: 'Incorrect email.' });
        const isMatch = await bcrypt.compare(password, user.password);
        if (!isMatch) return done(null, false, { message: 'Incorrect password.' });
        return done(null, user);
      } catch (err) {
        return done(err);
      }
    }));
     
    passport.serializeUser((user, done) => {
      done(null, user.id);
    });
     
    passport.deserializeUser(async (id, done) => {
      try {
        const user = await User.findById(id);
        done(null, user);
      } catch (err) {
        done(err);
      }
    });
     
    module.exports = passport;
  2. Authentication Middleware (authMiddleware.js):

    const ensureAuthenticated = (req, res, next) => {
      if (req.isAuthenticated()) {
        return next();
      }
      res.redirect('/login');
    };
     
    module.exports = { ensureAuthenticated };

API Structure

Authentication Routes:

Geolocation Routes:

Admin Routes:


5. Google Maps API Integration

Display Office Location and Geofencing:


6. PWA Conversion and TWA Implementation

PWA Setup:

TWA Conversion:

  1. Generate Android Project:

    Use tools like bubblewrap to create a TWA from your PWA:

    npx @bubblewrap/cli init
  2. Configure twa-manifest.json:

    Ensure the file correctly points to your web app and set necessary settings.

  3. Build and Deploy:

    Build the project using Android Studio and deploy it to the Play Store.


Conclusion

This comprehensive guide outlines the full-stack development approach for the geolocation-based attendance tracking app. It includes setting up the environment, designing the backend and database, integrating Google Maps, implementing authentication with Passport.js, and converting the PWA to a TWA. The structure and code snippets provided should help in building a robust, scalable, and user-friendly application.