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
| Parameter | Location | Type | Description |
|---|
pastorId | URL path | String | The profile ID of the pastor creating the church |
name | Body | String | Unique church name |
address | Body | String | Church physical address |
supportcontact | Body | Object | Contact 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
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",
});
}
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,
});
}
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:
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"
}
}'
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"
}'
Pastor views church members
curl -X GET http://localhost:3001/api/church/getchurches/507f1f77bcf86cd799439012 \
-H "Authorization: Bearer <pastor-token>"
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