Skip to content

SarahSchoonmaker/KindredPal

Repository files navigation

KindredPal

Community-centered peer support platform connecting people through shared life experiences.

KindredPal helps people find their people β€” through support groups, local meetups, and genuine connections built on common values, life stages, and challenges. Available on web and iOS.


πŸ“± Platform Overview

Surface Technology Hosting
iOS Mobile React Native (Expo) TestFlight
Web App React 18, React Router Vercel
Backend API Node.js, Express Railway
Database MongoDB Atlas, Mongoose Atlas Cloud
Real-time Socket.IO Railway
Media Cloudinary Cloud
Email Resend Cloud

✨ Features

πŸ‘₯ Community Groups

  • Discover β€” Browse public groups by category, keyword, city, state, or distance
  • Create β€” Start a group with name, category, location, and privacy setting
  • My Groups β€” Dedicated tab showing groups you've joined or created
  • Group Chat β€” Real-time messaging for group members via Socket.IO
  • Members β€” View all members, send connection requests, or message directly
  • Invitations β€” Admins can invite connections to private groups
  • Edit & Delete β€” Group admins can edit details; creators can delete

🀝 Connections

  • Send connection requests to people you share a group with
  • Accept, decline, or ignore incoming requests
  • View your connections list with profile photos and bios
  • Message any connection directly
  • Navigate to a connection's full profile

πŸ“… Meetups

  • Create in-person or virtual meetups and invite your connections
  • RSVP Going / Maybe / Not Going
  • Guest list with organizer shown first
  • Email and push notifications for new invites
  • My Groups widget on Meetups tab refreshes on every focus

πŸ’¬ Messaging

  • Real-time direct messages between connected users
  • Group chat per community group
  • Unread badge counts updated every 30 seconds and on app foreground

πŸ‘€ Profiles

  • Profile photo (Cloudinary upload)
  • Life stage, family situation, core values (up to 3)
  • Faith, political beliefs, bio, location
  • Push notification preferences

πŸ”” Notifications

  • Expo push notifications for meetup invites and new connections
  • Email notifications via Resend for group invites, meetup invites, password reset
  • Tab bar badges for messages, meetup invites, group invites, connection requests

πŸ—‚ Group Categories

🀲 Caregiver Support 🌿 Grief & Loss πŸƒ Sober & Clean Living
πŸ‘Ά New Parent Support πŸŽ—οΈ Chronic Illness Support 🧘 Anxiety & Mental Wellness
πŸŽ–οΈ Veteran Support 🌻 Senior Wellness πŸ’™ Loneliness & Social Connection
🌱 Divorce Recovery πŸ™ Faith & Spiritual Support πŸ”„ Life Transitions
πŸ•ŠοΈ Trauma Recovery πŸ’› Cancer Support πŸ‘¨β€πŸ‘§ Single Parent Support
⭐ Addiction Recovery πŸ¦‹ Autism & Special Needs Families 🌟 Singles Social Support
πŸ’‘ Married No Kids πŸ’Ό Career Change Support πŸ’° Financial Recovery
πŸƒ Sports & Fitness 🎯 Local Activity Groups

πŸ— Architecture

Navigation Structure (Mobile)

Root Stack Navigator
β”œβ”€β”€ Login / Signup
β”œβ”€β”€ MainTabs (Bottom Tab Navigator)
β”‚   β”œβ”€β”€ Groups        ← Discover + My Groups tabs
β”‚   β”œβ”€β”€ Connections   ← My connections + pending requests
β”‚   β”œβ”€β”€ Messages      ← Direct message conversations
β”‚   β”œβ”€β”€ Meetups       ← Upcoming meetups + My Groups widget
β”‚   └── Profile       ← Edit profile, settings
β”œβ”€β”€ GroupDetail
β”œβ”€β”€ CreateGroup
β”œβ”€β”€ MemberProfile
β”œβ”€β”€ UserProfile
β”œβ”€β”€ Chat
β”œβ”€β”€ MeetupDetails
β”œβ”€β”€ EditProfile
β”œβ”€β”€ Preferences
β”œβ”€β”€ BlockedUsers
└── WebView

State Management Pattern

KindredPal uses local React state with an optimistic-update + route params pattern:

  • Optimistic updates β€” UI updates instantly from local data, then a delayed server fetch confirms after 1–1.5s
  • Route params for cross-screen updates β€” after create/edit/delete, screens navigate back with newGroup / updatedGroup / deletedGroupId params; GroupsScreen patches both Discover and My Groups lists immediately
  • useFocusEffect β€” every tab screen re-fetches on focus so data stays current
  • filtersRef pattern β€” filter state lives in a useRef so fetchGroups has stable [] deps and never recreates

Key Navigation Note

Screens inside MainTabs cannot directly reach root stack screens with plain navigation.navigate(). Use either:

// From a tab screen β†’ root stack screen
navigation.getParent()?.navigate("MemberProfile", { userId });

// From a root stack screen β†’ back to a tab with params
navigation.navigate("MainTabs", {
  screen: "Groups",
  params: { updatedGroup: {...}, timestamp: Date.now() },
});

πŸ›  Tech Stack

Mobile      React Native (Expo SDK)
            React Navigation v6 (native stack + bottom tabs)
            React Native Paper, Lucide React Native
            Expo SecureStore, Expo Notifications

Web         React 18, React Router
            CSS Modules, Lucide React

Backend     Node.js, Express
            Mongoose (MongoDB ODM)
            Socket.IO (real-time messaging)
            JWT authentication
            Helmet, express-rate-limit, express-mongo-sanitize

Services    MongoDB Atlas
            Cloudinary (media storage)
            Resend (transactional email)
            Railway (backend hosting)
            Vercel (web hosting)
            EAS Build (iOS builds)

πŸ“‘ API Reference

All routes require Authorization: Bearer <token> except /api/auth/*.

Method Route Description
POST /api/auth/signup Create account
POST /api/auth/login Login, returns JWT
POST /api/auth/forgot-password Send reset email
POST /api/auth/reset-password Reset with token
GET /api/groups Discover public groups (filterable)
GET /api/groups/my Groups current user has joined/created
GET /api/groups/my-invites Pending group invitations
GET /api/groups/:id Single group detail
POST /api/groups Create a group
PUT /api/groups/:id Edit group (admin only)
DELETE /api/groups/:id Soft-delete group (creator only)
POST /api/groups/:id/join Join or request to join
POST /api/groups/:id/leave Leave a group
POST /api/groups/:id/invite/:userId Invite a connection
POST /api/groups/:id/rsvp-invite Accept/maybe/decline invite
GET /api/groups/:id/members List group members
GET /api/connections My accepted connections
GET /api/connections/requests Pending requests received
POST /api/connections/request/:userId Send connection request
POST /api/connections/accept/:id Accept a request
POST /api/connections/decline/:id Decline a request
DELETE /api/connections/:id Remove a connection
GET /api/connections/status/:userId Check connection status
GET /api/meetups My meetups
POST /api/meetups Create a meetup
PUT /api/meetups/:id Edit meetup
DELETE /api/meetups/:id Delete meetup
POST /api/meetups/:id/rsvp RSVP to a meetup
GET /api/users/profile/:userId Get any user's profile
PUT /api/users/profile Update current user's profile
GET /api/users/counts Badge counts (messages, invites, requests)
GET /api/messages/conversations All direct message conversations
GET /api/messages/:userId Messages with a specific user
POST /api/messages Send a direct message
GET /api/groups/:groupId/messages Group chat messages
POST /api/groups/:groupId/messages Send group chat message

πŸ—ƒ Data Models

User

name, email, password (bcrypt)
age, bio, profilePhoto, additionalPhotos
city, state, latitude, longitude
religion (String), politicalBeliefs (String)
lifeStage ([String]), familySituation ([String]), coreValues ([String], max 3)
causes ([String])
likes, passed, matches, blockedUsers (ObjectId refs)
pushTokens, emailNotifications
isVerified, onboardingComplete, isActive, isDeleted

Group

name, description, category
city, state, isNationwide, isPrivate
coverPhoto, tags
createdBy, members, admins (User refs)
pendingRequests, invitedUsers, maybeUsers
isActive (soft delete), isSeeded, memberCount

Connection

from, to (User refs β€” unique pair)
status: 'pending' | 'accepted' | 'declined'
message (optional), sharedGroupId

Meetup

title, description, dateTime
location: { address, city, state, zipCode }
creator, invitedUsers (User refs)
rsvps: [{ user, status: 'going' | 'maybe' | 'not-going' }]
maxAttendees, isActive

πŸš€ Deployment

Backend (Railway)

Auto-deploys from GitHub main. Set environment variables in Railway dashboard.

MONGODB_URI=
JWT_SECRET=
CLOUDINARY_CLOUD_NAME=
CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
RESEND_API_KEY=
CLIENT_URL=
NODE_ENV=production
PORT=                   # set automatically by Railway

Web (Vercel)

Auto-deploys from GitHub main. Set REACT_APP_API_URL in Vercel dashboard.

Mobile (EAS)

npx eas build --platform ios --profile preview

Submit to TestFlight after build completes.


πŸ’» Local Development

# Backend
cd backend
npm install
cp .env.example .env   # fill in your env vars
npm run dev            # runs on :5000

# Web
cd web
npm install
npm start              # runs on :3000

# Mobile (phone on same WiFi)
cd mobile
npm install
npx expo start --lan

# Mobile (different network)
npx expo start --tunnel

πŸ”’ Security

Measure Implementation
Authentication JWT, 7-day expiry, verified on every protected route
Passwords bcrypt, 12 salt rounds
Rate limiting 500 req/15min general Β· 10 req/15min auth Β· 20 req/15min profile
NoSQL injection express-mongo-sanitize strips $ and . from request bodies
HTTP hardening Helmet β€” CSP, X-Frame-Options, HSTS, and more
CORS Explicit allowlist β€” kindredpal.com, Vercel preview URLs, localhost
Soft deletes Users and groups use isDeleted/isActive flags, never hard-deleted
Connection gating Users must share an active group before sending a connection request

πŸ“ Project Structure

KindredPal/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ middleware/
β”‚   β”‚   └── auth.js              # JWT verification
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   β”œβ”€β”€ User.js
β”‚   β”‚   β”œβ”€β”€ Group.js
β”‚   β”‚   β”œβ”€β”€ Connection.js
β”‚   β”‚   β”œβ”€β”€ Meetup.js
β”‚   β”‚   β”œβ”€β”€ Message.js
β”‚   β”‚   └── GroupMessage.js
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ auth.js
β”‚   β”‚   β”œβ”€β”€ users.js
β”‚   β”‚   β”œβ”€β”€ groups.js
β”‚   β”‚   β”œβ”€β”€ connections.js
β”‚   β”‚   β”œβ”€β”€ meetups.js
β”‚   β”‚   β”œβ”€β”€ messages.js
β”‚   β”‚   └── group-messages.js
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   └── notificationService.js
β”‚   └── server.js
β”œβ”€β”€ mobile/
β”‚   └── src/
β”‚       β”œβ”€β”€ screens/
β”‚       β”‚   β”œβ”€β”€ GroupsScreen.js
β”‚       β”‚   β”œβ”€β”€ GroupDetailScreen.js
β”‚       β”‚   β”œβ”€β”€ CreateGroupScreen.js
β”‚       β”‚   β”œβ”€β”€ ConnectionsScreen.js
β”‚       β”‚   β”œβ”€β”€ MemberProfileScreen.js
β”‚       β”‚   β”œβ”€β”€ MeetupsScreen.js
β”‚       β”‚   β”œβ”€β”€ MeetupDetailsScreen.js
β”‚       β”‚   β”œβ”€β”€ MessagesScreen.js
β”‚       β”‚   β”œβ”€β”€ ChatScreen.js
β”‚       β”‚   β”œβ”€β”€ ProfileScreen.js
β”‚       β”‚   β”œβ”€β”€ EditProfileScreen.js
β”‚       β”‚   └── ...
β”‚       β”œβ”€β”€ services/
β”‚       β”‚   └── api.js
β”‚       └── context/
β”‚           └── SocketContext.js
└── web/
    └── src/
        β”œβ”€β”€ pages/
        └── services/
            └── api.js

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors