Skip to main content

Overview

Church operations form the core of the Church Management System. This guide covers creating churches, managing membership, and communicating with members.

Church Data Structure

Each church contains:
  • Pastor - User profile ID of the church pastor (creator)
  • Name - Unique church name
  • Address - Physical location
  • Support Contact - Phone, email, and website
  • Members - Array of user profile IDs

Creating a Church

Prerequisites

Only users with the pastor role can create churches. Ensure you’ve registered as a pastor and completed your profile.

Create Church Endpoint

POST /api/church/createchurch/:pastorId
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "Grace Community Church",
  "address": "789 Faith Avenue, Springfield, IL 62701",
  "supportcontact": {
    "phone": "+1-555-0123",
    "email": "[email protected]",
    "website": "https://gracecommunity.org"
  }
}

Request Parameters

ParameterLocationTypeDescription
pastorIdURL pathStringThe profile ID of the pastor creating the church
nameBodyStringUnique church name
addressBodyStringChurch physical address
supportcontactBodyObjectContact information

Church Creation Logic

The system automatically handles church creation with validation:
const createAchurch = async (req, res) => {
  const pastorID = req.params.pastorId;
  const churchData = req.body;

  try {
    // Check if church name already exists
    let church = await churchObject.findOne({ name: req.body.name });

    if (church) {
      res.status(200).send({
        success: false,
        message: `Church Name Already exists`,
        data: church,
      });
    } else {
      // Create church with pastor as first member
      church = churchObject({
        pastor: pastorID,
        ...churchData,
        members: [pastorID], // Pastor automatically becomes first member
      });

      await church.save();

      // Populate pastor and members data
      church = await churchObject
        .findById(church._id)
        .populate({
          path: "pastor",
          select: "-_id -createdAt -updatedAt -__v",
          populate: {
            path: "authDetails",
            select: "-_id -password -createdAt -updatedAt -__v",
          },
        })
        .populate({
          path: "members",
          select: "-_id -createdAt -updatedAt -__v",
          populate: {
            path: "authDetails",
            select: "-_id -password -createdAt -updatedAt -__v",
          },
        });

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

Success Response

{
  "success": true,
  "message": "Church Created",
  "data": {
    "_id": "507f1f77bcf86cd799439011",
    "name": "Grace Community Church",
    "address": "789 Faith Avenue, Springfield, IL 62701",
    "supportcontact": {
      "phone": "+1-555-0123",
      "email": "[email protected]",
      "website": "https://gracecommunity.org"
    },
    "pastor": {
      "name": "Pastor John Smith",
      "phoneNumber": 5551234567,
      "authDetails": {
        "email": "[email protected]",
        "role": "pastor"
      }
    },
    "members": [
      {
        "name": "Pastor John Smith",
        "phoneNumber": 5551234567
      }
    ]
  }
}
The pastor who creates the church is automatically added as the first member of the members array.

Managing Church Membership

Join a Church

Members can join any church using the church ID:
POST /api/church/:id/join
Authorization: Bearer <token>
Content-Type: application/json

{
  "userId": "507f1f77bcf86cd799439012"
}

Join Church Logic

1

Verify church exists

const theChurch = await churchObject.findById(churchId);

if (!theChurch) {
  return res.status(404).send({
    success: false,
    message: "Unable to join church",
    data: "Church with this Id does not exist",
  });
}
2

Check existing membership

const alreadyAmember = await churchObject
  .findOne({ _id: churchId, members: userID })
  .populate("pastor", "name -_id");

if (alreadyAmember) {
  return res.status(200).send({
    success: false,
    message: "You are already a member of this church",
    data: alreadyAmember,
  });
}
3

Add member to church

theChurch.members.push(userID);
await theChurch.save();

res.status(200).send({
  success: true,
  message: `You have successfully joined ${theChurch.name}`,
  data: theChurchNow,
});

Exit a Church

Members can leave a church they’ve joined:
POST /api/church/:id/exit
Authorization: Bearer <token>
Content-Type: application/json

{
  "userId": "507f1f77bcf86cd799439012"
}

Exit Church Logic

const exitAChurch = async (req, res) => {
  const churchId = req.params.id;
  const userID = req.body.userId;

  try {
    const theChurch = await churchObject.findById(churchId);

    if (theChurch) {
      const isAmember = await churchObject
        .findOne({ _id: churchId, members: userID })
        .populate("pastor", "name -_id");

      if (isAmember) {
        // Remove user from members array
        theChurch.members = theChurch.members.filter(
          (member) => member.toString() !== userID.toString()
        );
        await theChurch.save();

        res.status(200).send({
          success: true,
          message: `You have successfully exited ${isAmember.name}`,
          data: isAmember,
        });
      } else {
        res.status(400).send({
          success: false,
          message: "Unable to exit church",
          data: "You are not a member of this church",
        });
      }
    }
  } catch (err) {
    res.status(500).send({
      success: false,
      message: "Unable to exit church",
      data: err.message,
    });
  }
};

Viewing Churches

Get Pastor’s Churches

Pastors can view all churches they’ve created:
GET /api/church/getchurches/:pastorId
Authorization: Bearer <token>

Response Example

{
  "success": true,
  "message": "You have 2 church(es)",
  "data": [
    {
      "_id": "507f1f77bcf86cd799439011",
      "name": "Grace Community Church",
      "address": "789 Faith Avenue, Springfield, IL 62701",
      "supportcontact": {
        "phone": "+1-555-0123",
        "email": "[email protected]",
        "website": "https://gracecommunity.org"
      },
      "pastor": {
        "name": "Pastor John Smith",
        "phoneNumber": 5551234567
      },
      "members": [
        { "name": "Pastor John Smith" },
        { "name": "Jane Doe" },
        { "name": "Bob Wilson" }
      ]
    }
  ]
}

Get User’s Churches

Members can view all churches they belong to:
GET /api/church/user/:id
Authorization: Bearer <token>

Implementation

const getAllUserChurches = async (req, res) => {
  const userId = req.params.id;

  try {
    const theUserChurches = await churchObject
      .find({ members: userId })
      .select("-__v -createdAt -updatedAt -members")
      .populate("pastor", "-_id -__v -createdAt -updatedAt -authDetails");

    if (theUserChurches.length > 0) {
      res.status(200).send({
        success: true,
        message: `You are in ${theUserChurches.length} church(es)`,
        data: theUserChurches,
      });
    } else {
      res.status(404).send({
        success: false,
        message: "Unable to fetch churches",
        data: "You are not a member of any church yet",
      });
    }
  } catch (err) {
    res.status(500).send({
      success: false,
      message: "Unable to fetch churches",
      data: err.message,
    });
  }
};

Church Communications

Send Email to All Members

Pastors can send emails to all church members:
POST /api/church/sendemailtoall
Authorization: Bearer <token>
Content-Type: application/json

{
  "subject": "Sunday Service Announcement",
  "message": "<p>Join us this Sunday at 10 AM for our worship service!</p>",
  "churchId": "507f1f77bcf86cd799439011",
  "pastorId": "507f1f77bcf86cd799439012"
}

Email Sending Logic

const sendEmailToAllMembers = async (req, res) => {
  try {
    const { subject, message, churchId, pastorId } = req.body;

    // Get church with populated member emails
    const theChurch = await churchObject.findOne({ _id: churchId }).populate({
      path: "members",
      populate: {
        path: "authDetails",
        select: "email",
      },
    });

    if (theChurch) {
      // Verify sender is the pastor
      if (theChurch.pastor.toString() === pastorId) {
        const members = theChurch.members;

        if (!members.length) {
          return res.status(404).json({ message: "No members found" });
        }

        // Extract all member emails
        const emails = members.map((m) => m.authDetails.email);

        // Send email using BCC to protect member privacy
        await transporter.sendMail({
          from: `${theChurch.name}`,
          bcc: emails, // Blind carbon copy for privacy
          subject: subject,
          html: `<p>${message}</p>`,
        });

        res.status(200).send({
          success: true,
          message: `Email sent to ${emails.length} member(s)`,
          data: emails,
        });
      } else {
        res.status(400).send({
          success: false,
          message: "Unable to send emails",
          data: "You are not the pastor of this church",
        });
      }
    }
  } catch (err) {
    res.status(500).send({
      success: false,
      message: "Unable to send emails",
      data: err.message,
    });
  }
};
Emails are sent using BCC (Blind Carbon Copy) to protect member privacy. No member can see other members’ email addresses.

Complete Church Workflow

Here’s a complete example of church operations:
1

Pastor creates a church

curl -X POST http://localhost:3001/api/church/createchurch/507f1f77bcf86cd799439012 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <pastor-token>" \
  -d '{
    "name": "Grace Community Church",
    "address": "789 Faith Avenue, Springfield, IL 62701",
    "supportcontact": {
      "phone": "+1-555-0123",
      "email": "[email protected]",
      "website": "https://gracecommunity.org"
    }
  }'
2

Member joins the church

curl -X PATCH http://localhost:3001/api/church/joinchurch/507f1f77bcf86cd799439011 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <member-token>" \
  -d '{
    "userId": "507f1f77bcf86cd799439013"
  }'
3

Pastor views church members

curl -X GET http://localhost:3001/api/church/getchurches/507f1f77bcf86cd799439012 \
  -H "Authorization: Bearer <pastor-token>"
4

Pastor sends announcement to members

curl -X POST http://localhost:3001/api/church/sendemailtoall \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <pastor-token>" \
  -d '{
    "subject": "Sunday Service Update",
    "message": "<p>Service starts at 10 AM this Sunday!</p>",
    "churchId": "507f1f77bcf86cd799439011",
    "pastorId": "507f1f77bcf86cd799439012"
  }'

Virtual Fields

The church model includes a virtual field for counting active members:
churchSchema.virtual("activeMembersCount").get(function () {
  return this.members?.length || 0;
});
This field is calculated dynamically and not stored in the database.

Error Handling

Common Errors

Duplicate Church Name:
{
  "success": false,
  "message": "Church Name Already exists",
  "data": { /* existing church data */ }
}
Church Not Found:
{
  "success": false,
  "message": "Unable to join church",
  "data": "Church with this Id does not exist"
}
Already a Member:
{
  "success": false,
  "message": "You are already a member of this church",
  "data": { /* church data */ }
}
Not a Member:
{
  "success": false,
  "message": "Unable to exit church",
  "data": "You are not a member of this church"
}
Unauthorized Email Send:
{
  "success": false,
  "message": "Unable to send emails",
  "data": "You are not the pastor of this church"
}

Best Practices

Important Considerations:
  • Only pastors can create churches and send emails
  • Church names must be unique across the system
  • The pastor is automatically added as the first member
  • Members can join and leave churches freely
  • Email addresses are protected using BCC
  • Verify pastor ID matches the authenticated user before allowing church creation
Recommendations:
  • Store church IDs on the client side for quick access
  • Cache member lists to reduce database queries
  • Implement rate limiting on email sending to prevent abuse
  • Consider adding church categories or denominations for better organization
  • Add image uploads for church logos and photos

Next Steps

Build docs developers (and LLMs) love