By the end of this lesson, you will understand the essential patterns that make apps "connected" - how users authenticate, stay updated in real-time, interact socially, and receive meaningful notifications.
🔗 The Connection Pattern: Modern mobile apps feel "alive" because they connect users to each other and to live information. This isn't about individual technologies - it's about understanding the overall pattern of how apps create connected experiences.
Connected features work together to create seamless user experiences:
Pillar | Purpose | User Benefit | Example |
---|---|---|---|
Authentication | Identity & Security | "I am who I say I am" | Login with Google |
Real-time Updates | Live Information | "I see changes as they happen" | Live chat messages |
Social Features | Human Connection | "I can connect with others" | Friend requests |
Notifications | Timely Awareness | "I know when something matters" | New message alerts |
Authentication is how apps verify user identity and build trust between users.
// Basic user authentication flow
class SimpleAuth {
constructor() {
this.currentUser = null;
}
async signUp(email, password) {
try {
// Create new user account
const user = await createAccount({
email: email,
password: password,
joinDate: new Date()
});
// Send verification email
await sendVerificationEmail(user.email);
return {
success: true,
message: "Check your email to verify account"
};
} catch (error) {
return {
success: false,
message: "Sign up failed. Please try again."
};
}
}
async signIn(email, password) {
try {
const user = await validateCredentials(email, password);
if (user) {
this.currentUser = user;
return { success: true, user: user };
}
return { success: false, message: "Invalid credentials" };
} catch (error) {
return { success: false, message: "Sign in failed" };
}
}
signOut() {
this.currentUser = null;
return { success: true, message: "Signed out successfully" };
}
}
// Using existing accounts for faster onboarding
async function signInWithGoogle() {
try {
const result = await GoogleSignIn.signIn();
// Create or find user profile
const user = await findOrCreateUser({
email: result.user.email,
name: result.user.name,
profileImage: result.user.photo,
authProvider: 'google'
});
return { success: true, user: user };
} catch (error) {
return { success: false, message: "Google sign-in failed" };
}
}
Real-time features make apps feel alive by showing changes as they happen.
// Simple WebSocket connection for live updates
class LiveUpdates {
constructor(userId) {
this.userId = userId;
this.socket = null;
}
connect() {
this.socket = new WebSocket('ws://app-server.com/live');
this.socket.onopen = () => {
console.log('Connected to live updates');
// Join user-specific channel
this.socket.send(JSON.stringify({
type: 'join',
userId: this.userId
}));
};
this.socket.onmessage = (event) => {
const update = JSON.parse(event.data);
this.handleLiveUpdate(update);
};
}
handleLiveUpdate(update) {
switch (update.type) {
case 'new_message':
this.showNewMessage(update.data);
break;
case 'friend_online':
this.updateFriendStatus(update.data);
break;
case 'content_updated':
this.refreshContent(update.data);
break;
}
}
sendUpdate(data) {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify(data));
}
}
}
// For simpler apps, regular checking can work
class SimpleUpdates {
constructor() {
this.lastCheckTime = new Date();
}
startChecking() {
setInterval(async () => {
try {
const updates = await fetch(
`/api/updates?since=${this.lastCheckTime.toISOString()}`
);
const newUpdates = await updates.json();
if (newUpdates.length > 0) {
this.handleUpdates(newUpdates);
this.lastCheckTime = new Date();
}
} catch (error) {
console.log('Update check failed:', error);
}
}, 5000); // Check every 5 seconds
}
}
Social features help users connect and interact with each other.
// Simple user profile system
function createUserProfile(userData) {
return {
id: generateUserId(),
displayName: userData.displayName,
profileImage: userData.profileImage,
bio: userData.bio || "",
interests: userData.interests || [],
joinDate: new Date(),
// Privacy settings
privacy: {
showEmail: false,
allowMessages: true,
publicProfile: true
}
};
}
// Basic friend/connection system
class UserConnections {
constructor(userId) {
this.userId = userId;
this.friends = new Set();
}
async sendFriendRequest(targetUserId) {
const request = {
from: this.userId,
to: targetUserId,
message: "Hi! I'd like to connect.",
status: 'pending',
createdAt: new Date()
};
await saveFriendRequest(request);
// Notify the other user
await sendNotification(targetUserId, {
type: 'friend_request',
title: "New friend request!",
message: "Someone wants to connect with you."
});
return { success: true };
}
async acceptFriendRequest(requestId) {
const request = await getFriendRequest(requestId);
// Create mutual friendship
this.friends.add(request.from);
await addFriend(request.from, this.userId);
return { success: true, message: "You're now friends!" };
}
}
// Basic content sharing between users
async function shareContent(content) {
const post = {
id: generatePostId(),
author: content.authorId,
text: content.text,
image: content.image || null,
createdAt: new Date(),
likes: 0,
comments: []
};
await savePost(post);
// Notify friends about new post
const friends = await getFriends(content.authorId);
for (const friend of friends) {
await sendNotification(friend.id, {
type: 'new_post',
message: `${content.authorName} shared something new`
});
}
return { success: true, postId: post.id };
}
Notifications keep users informed about important updates without overwhelming them.
// Thoughtful notification management
class SmartNotifications {
constructor() {
this.notificationTypes = {
urgent: { priority: 'high', sound: true },
social: { priority: 'medium', sound: false },
update: { priority: 'low', sound: false }
};
}
async sendNotification(userId, notification) {
// Check user preferences
const userSettings = await getUserNotificationSettings(userId);
if (!userSettings[notification.type]) {
return; // User has this type disabled
}
// Check timing (don't disturb during quiet hours)
if (this.isQuietTime() && notification.priority !== 'high') {
await scheduleNotificationForLater(userId, notification);
return;
}
// Send the notification
await deliverNotification(userId, {
title: notification.title,
message: notification.message,
data: notification.data,
priority: this.notificationTypes[notification.type].priority
});
}
isQuietTime() {
const hour = new Date().getHours();
return hour < 8 || hour > 21; // Before 8 AM or after 9 PM
}
}
// Let users control their notification experience
class NotificationSettings {
constructor(userId) {
this.userId = userId;
this.defaultSettings = {
messages: true,
friendRequests: true,
posts: false,
quietHours: {
enabled: true,
start: '22:00',
end: '08:00'
}
};
}
async updateSettings(newSettings) {
const settings = { ...this.defaultSettings, ...newSettings };
await saveNotificationSettings(this.userId, settings);
return { success: true };
}
async shouldNotify(notificationType, currentTime) {
const settings = await this.getUserSettings();
// Check if type is enabled
if (!settings[notificationType]) {
return false;
}
// Check quiet hours
if (settings.quietHours.enabled &&
this.isInQuietHours(currentTime, settings.quietHours)) {
return false;
}
return true;
}
}
These features combine to create seamless user experiences:
// Example: Real-time messaging with all connected features
class ConnectedMessaging {
constructor(currentUser) {
this.currentUser = currentUser;
this.auth = new SimpleAuth();
this.liveUpdates = new LiveUpdates(currentUser.id);
this.notifications = new SmartNotifications();
}
async sendMessage(recipientId, messageText) {
// 1. Authentication: Verify user can send messages
if (!this.auth.isAuthenticated()) {
return { error: "Please sign in to send messages" };
}
// 2. Social: Check if users are connected
const canMessage = await this.canUserMessage(recipientId);
if (!canMessage) {
return { error: "You can only message friends" };
}
// 3. Real-time: Send message immediately
const message = {
id: generateMessageId(),
from: this.currentUser.id,
to: recipientId,
text: messageText,
timestamp: new Date()
};
await saveMessage(message);
this.liveUpdates.sendUpdate({
type: 'new_message',
data: message
});
// 4. Notifications: Alert the recipient
await this.notifications.sendNotification(recipientId, {
type: 'messages',
title: 'New message',
message: `${this.currentUser.name} sent you a message`
});
return { success: true, messageId: message.id };
}
async canUserMessage(recipientId) {
const friendships = await getUserFriends(this.currentUser.id);
return friendships.includes(recipientId);
}
}
Research Question: How do connected features change user behavior and app engagement?
Your Investigation:
Key Questions to Explore:
// Phase 1: Basic authentication
const app = {
auth: new SimpleAuth(),
users: new Map()
};
// Phase 2: Add basic social features
app.social = new UserConnections();
app.profiles = new Map();
// Phase 3: Add real-time capabilities
app.liveUpdates = new LiveUpdates();
// Phase 4: Add smart notifications
app.notifications = new SmartNotifications();
For your personal app projects:
Remember: Connected features should enhance your app's core purpose, not distract from it.
You learned:
Next: You'll explore advanced mobile development patterns that help you build more sophisticated and polished applications.