Skip to main content

Overview

The Church Management System uses a two-tier user system: authentication credentials stored separately from profile information. This guide covers user registration, login, and profile management workflows.

User Roles

The system supports two primary roles:
  • Pastor - Can create churches, manage donations, and send communications
  • Member - Can join churches, make donations, and view information

User Registration

Register a New User

Create a new user account with email and password:
POST /api/auth/register
Content-Type: application/json

{
  "email": "[email protected]",
  "password": "securePassword123",
  "role": "member",
  "invitedBy": "[email protected]"
}

Registration Validation

The registration endpoint performs several validations:
// Password must be at least 6 characters
if (req.body.password.length < 6) {
  return res.status(400).send({
    success: false,
    message: "Password must be at least 6 characters",
  });
}

Success Response

{
  "success": true,
  "message": "Registeration Successful",
  "data": "A verification link has been sent to you. Kindly verify your email address"
}
After registration, users must complete their profile before accessing full functionality. The isProfileComplete flag tracks this status.

User Authentication

Login Flow

Authenticate users and receive a JWT token:
POST /api/auth/login
Content-Type: application/json

{
  "email": "[email protected]",
  "password": "securePassword123"
}

Login Process

1

Email verification

The system first checks if a user exists with the provided email:
const theUser = await authObject.findOne({ email: body.email });

if (!theUser) {
  return res.status(404).send({
    success: false,
    message: "Log in not Successful",
    data: `User with email ${body.email} not found`,
  });
}
2

Password comparison

Compare the provided password with the hashed password:
const isMatch = await bcrypt.compare(body.password, theUser.password);

if (!isMatch) {
  return res.status(400).send({
    success: false,
    message: "Log in not Successful",
    data: "Incorrect Email or Password",
  });
}
3

JWT token generation

Generate a JWT token valid for 1 hour:
const token = jwt.sign(
  { id: theUser._id, role: theUser.role },
  process.env.JWT_SECRET,
  { expiresIn: "1h" }
);
4

Profile fetching

Retrieve the user’s profile information:
const userProfile = await fetchProfileForLogin(theUser._id);

Login Response

{
  "success": true,
  "message": "Login Successful",
  "data": {
    "User": {
      "email": "[email protected]",
      "role": "member",
      "profile": {
        "_id": "507f1f77bcf86cd799439011",
        "name": "John Doe",
        "age": 30,
        "phoneNumber": 1234567890
      },
      "invitedBy": "[email protected]",
      "isProfileComplete": true,
      "createdAt": "2024-01-15T10:30:00.000Z"
    },
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}
Store the JWT token securely on the client side. Include it in the Authorization header for all authenticated requests:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Profile Management

Create or Update Profile

Users must complete their profile after registration. This endpoint handles both creation and updates:
POST /api/users/createprofile
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "John Doe",
  "address": "123 Main St, City, State 12345",
  "age": 30,
  "dob": "1994-05-15",
  "phoneNumber": 1234567890
}

Profile Data Requirements

FieldTypeValidationRequired
nameStringAny stringYes
addressStringAny stringYes
ageNumberMin: 13, Max: 99Yes
dobDateFormat: YYYY-MM-DD, must be past dateYes
phoneNumberNumberValid phone numberYes

Profile Creation Logic

const createOrUpdateProfile = async (req, res) => {
  const userId = req.theUser.id; // From JWT token
  const profileData = req.body;

  try {
    let profile = await profileObject.findOne({ authDetails: userId });

    if (profile) {
      // Update existing profile
      profile = await profileObject
        .findOneAndUpdate({ authDetails: userId }, { ...profileData })
        .populate("authDetails", "-password -_id -createdAt -updatedAt -__v");

      await authObject.findByIdAndUpdate(userId, {
        isProfileComplete: true,
      });

      res.status(201).send({
        success: true,
        message: "Profile Updated",
        data: profile,
      });
    } else {
      // Create new profile
      profile = profileObject({
        authDetails: userId,
        ...profileData,
      });

      await profile.save();
      await authObject.findByIdAndUpdate(userId, {
        isProfileComplete: true,
      });

      profile = await profileObject
        .findById(profile._id)
        .populate("authDetails", "-password -_id -createdAt -updatedAt -__v");

      res.status(201).send({
        success: true,
        message: "Profile Created",
        data: profile,
      });
    }
  } catch (err) {
    res.status(500).send({
      success: false,
      message: "Profile Creation not successful",
      data: err.message,
    });
  }
};

Get User Profile

Retrieve the authenticated user’s profile information:
GET /api/users/getprofile
Authorization: Bearer <token>

Profile Response

{
  "success": true,
  "message": "Profile found",
  "data": {
    "_id": "507f1f77bcf86cd799439011",
    "name": "John Doe",
    "address": "123 Main St, City, State 12345",
    "age": 30,
    "dob": "1994-05-15T00:00:00.000Z",
    "phoneNumber": 1234567890,
    "authDetails": {
      "email": "[email protected]",
      "role": "member",
      "invitedBy": "[email protected]",
      "isProfileComplete": true
    }
  }
}

Complete User Workflow

Here’s a typical user onboarding workflow:
1

Registration

User registers with email, password, and role:
curl -X POST http://localhost:3001/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "securePass123",
    "role": "member",
    "invitedBy": "[email protected]"
  }'
2

Login

User logs in and receives a JWT token:
curl -X POST http://localhost:3001/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "securePass123"
  }'
Save the token from the response.
3

Complete Profile

User completes their profile using the token:
curl -X POST http://localhost:3001/api/users/createprofile \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{
    "name": "Jane Member",
    "address": "456 Church Ave",
    "age": 28,
    "dob": "1996-03-20",
    "phoneNumber": 5551234567
  }'
4

Access Protected Resources

User can now access all features like joining churches and making donations.

Authentication Middleware

All protected endpoints require a valid JWT token. The middleware extracts the user ID from the token:
// Example of how the token is used in controllers
const userId = req.theUser.id; // Populated by auth middleware
Always check isProfileComplete before allowing users to perform church-related actions. Users should complete their profiles first.

Error Handling

Common Error Responses

Registration Errors:
// Duplicate email
{
  "success": false,
  "message": "Email already exists"
}

// Password too short
{
  "success": false,
  "message": "Password must be at least 6 characters"
}
Login Errors:
// User not found
{
  "success": false,
  "message": "Log in not Successful",
  "data": "User with email [email protected] not found"
}

// Wrong password
{
  "success": false,
  "message": "Log in not Successful",
  "data": "Incorrect Email or Password"
}
Profile Errors:
// Profile not found
{
  "success": false,
  "message": "Profile not found",
  "data": "You do not have any profile"
}

Security Best Practices

Important Security Considerations:
  • Passwords are hashed with bcrypt before storage (never stored in plain text)
  • JWT tokens expire after 1 hour
  • Emails are stored in lowercase for consistency
  • Email validation uses regex pattern matching
  • Role must be either “pastor” or “member”
  • Date of birth must be in the past
  • Age must be between 13-99 years

Next Steps

Build docs developers (and LLMs) love