Project Templates
Social Network
How to Create a Social Media Platform: Step-by-Step Guide (2025)
71 min
introduzione in questo tutorial, imparerai come costruire una piattaforma di social network simile a instagram utilizzando back4app come servizio backend back4app fornisce un backend gestito di parse server che semplifica l'autenticazione degli utenti, l'archiviazione dei dati, il caricamento di file e le funzionalità in tempo reale senza richiedere un'infrastruttura server complessa completando questo tutorial, costruirai un social network completo con autenticazione degli utenti (registrazione, accesso, reimpostazione della password) gestione del profilo creazione di post con caricamenti di immagini interazioni sociali (mi piace, commenti) messaggistica in tempo reale con indicatori di digitazione funzionalità di ricerca dei contenuti anteprima del social networkinterfaccia chatprofilo utentepagina feed in qualsiasi momento puoi accedere al codice completo su github requisiti per completare questo tutorial, avrai bisogno di un account back4app registrati per un account gratuito su back4app com https //www back4app com/ node js e npm installati sulla tua macchina locale installa node js (versione 14 x o successiva) e npm da nodejs org https //nodejs org/ comprensione di base di javascript e react editor di codice qualsiasi editor di codice moderno come visual studio code o sublime text passo 1 — configurare il tuo backend back4app per prima cosa, creiamo un nuovo progetto back4app e impostiamo lo schema del database per il nostro social network creare un nuovo progetto back4app accedi al tuo account back4app e vai al dashboard clicca su "crea una nuova app" inserisci "back4gram" come nome della tua app, seleziona la regione del server più vicina e clicca su "crea" comprendere lo schema del database la nostra rete sociale richiede le seguenti classi in back4app utente (già esistente per impostazione predefinita in parse) sarà esteso con campi aggiuntivi come bio e avatar post memorizza i post degli utenti, inclusi contenuti testuali e immagini commento memorizza i commenti sui post conversazione rappresenta una conversazione chat tra utenti messaggio messaggi individuali all'interno di una conversazione stato di digitazione monitora quando gli utenti stanno digitando in una conversazione creare classi di database creiamo queste classi nel tuo database back4app naviga alla sezione "database" nel tuo dashboard di back4app estendere la classe utente clicca sulla classe "utente" che esiste già aggiungi le seguenti colonne bio (tipo string) avatar (tipo file) seguaci (tipo numero, predefinito 0) seguente (tipo numero, predefinito 0) creazione della classe post clicca su "crea una classe" inserisci "post" come nome della classe e seleziona "crea una classe vuota" aggiungi le seguenti colonne contenuto (tipo stringa) autore (tipo puntatore a utente) immagine (tipo file) mi piace (tipo numero, predefinito 0) piaciutoda (tipo array) creato il (tipo data, aggiunto automaticamente) creazione della classe commento crea una nuova classe chiamata "commento" con queste colonne contenuto (tipo stringa) autore (tipo puntatore a utente) post (tipo puntatore a post) creato il (tipo data, aggiunto automaticamente) creazione della classe conversation crea una nuova classe chiamata "conversazione" con queste colonne partecipanti (tipo array) ultimomessaggio (tipo stringa) aggiornatoil (tipo data, aggiunto automaticamente) creazione della classe message crea una nuova classe chiamata "messaggio" con queste colonne testo (tipo string) mittente (tipo puntatore a utente) conversazione (tipo puntatore alla conversazione) creato il (tipo data, aggiunto automaticamente) creazione della classe typingstatus crea una nuova classe chiamata "typingstatus" con queste colonne utente (tipo puntatore a utente) conversazione (tipo puntatore alla conversazione) stascrivendo (tipo booleano) impostazione delle autorizzazioni della classe per proteggere i dati della tua applicazione, configura le liste di controllo accessi (acl) appropriate per ciascuna classe naviga nella sezione "sicurezza e chiavi" nel tuo dashboard di back4app sotto "sicurezza a livello di classe", configura i permessi per ogni classe ad esempio, sulla classe post accesso in lettura pubblico abilitato (tutti possono vedere i post) accesso in scrittura pubblico abilitato (gli utenti autenticati possono creare post) aggiungi clp per aggiornamento/cancellazione per limitare solo all'autore impostazione di livequery per funzionalità in tempo reale per abilitare funzionalità in tempo reale come messaggistica e indicatori di digitazione naviga su "impostazioni del server" nel tuo dashboard di back4app sotto "parse server", trova "livequery" e abilitalo aggiungi queste classi da monitorare tramite livequery messaggio stato di digitazione post (per aggiornamenti in tempo reale a mi piace e commenti) ottenere le chiavi della tua applicazione avrai bisogno delle chiavi della tua applicazione back4app per connettere il tuo frontend naviga su "impostazioni app" > "sicurezza e chiavi" annota le seguenti chiavi id applicazione chiave javascript url del server url del server livequery chiavi di sicurezza passo 2 — collegare il tuo frontend a back4app impostiamo la connessione tra il tuo frontend e il backend di back4app creazione di variabili d'ambiente crea un env local file nella radice del tuo progetto per memorizzare le tue credenziali di back4app react app parse app id=your application id react app parse js key=your javascript key react app parse server url=https //parseapi back4app com react app parse live query url=wss\ //your app id back4app io sostituisci i valori segnaposto con le tue credenziali effettive di back4app configurare il parse sdk con back4app crea un file di configurazione per inizializzare parse con le tue credenziali di back4app // src/utils/parseconfig js import parse from 'parse/dist/parse min js'; // initialize parse parse initialize( process env react app parse app id, process env react app parse js key ); parse serverurl = process env react app parse server url; // initialize live queries if (process env react app parse live query url) { parse livequeryserverurl = process env react app parse live query url; } export default parse; poi importa questa configurazione nel punto di ingresso della tua app // src/index js import react from 'react'; import reactdom from 'react dom/client'; import ' /index css'; import app from ' /app'; import ' /utils/parseconfig'; // import parse configuration const root = reactdom createroot(document getelementbyid('root')); root render( \<react strictmode> \<app /> \</react strictmode> ); passo 3 — implementazione dell'autenticazione con back4app il server parse di back4app fornisce un sistema di gestione degli utenti completo attraverso la parse user classe comprendere l'autenticazione dell'utente di parse la classe parse user è progettata specificamente per la gestione degli utenti memorizza le credenziali dell'utente (nome utente, email, password) gestisce lo stato di autenticazione gestisce automaticamente i token di sessione implementazione della registrazione dell'utente ecco come implementare la registrazione dell'utente con parse // signup function const handlesignup = async () => { try { // create a new user const user = new parse user(); user set('username', username); user set('email', email); user set('password', password); // additional user data user set('bio', ''); user set('followers', 0); user set('following', 0); // sign up the user await user signup(); // success user is automatically logged in console log('user registered successfully'); // navigate to feed or home page navigate('/feed'); } catch (error) { // handle specific parse errors console error('error signing up ', error message); if (error code === 202) { seterrors({ errors, username 'username already taken'}); } else if (error code === 203) { seterrors({ errors, email 'email already in use'}); } } }; implementazione del login utente ecco come implementare il login utente con parse // login function const handlelogin = async () => { try { // log in the user const user = await parse user login(username, password); // success user is logged in console log('user logged in successfully ', user getusername()); // navigate to feed or home page navigate('/feed'); } catch (error) { // handle login errors console error('error logging in ', error message); setloginerror(error message); } }; controllo utente corrente parse memorizza automaticamente il token di sessione, permettendoti di controllare se un utente è già connesso // check if user is already logged in const checkcurrentuser = async () => { try { const currentuser = await parse user current(); if (currentuser) { console log('current user ', currentuser getusername()); return currentuser; } return null; } catch (error) { console error('error checking current user ', error); return null; } }; implementazione del ripristino della password back4app fornisce un flusso di ripristino della password integrato // password reset function const handlepasswordreset = async () => { try { await parse user requestpasswordreset(email); // success email sent to user console log('password reset email sent'); setresetemailsent(true); } catch (error) { // handle reset errors console error('error requesting password reset ', error message); setreseterror(error message); } }; passo 4 — creazione e visualizzazione dei post ora implementiamo la creazione e il recupero dei post utilizzando back4app creazione di post ecco come creare un nuovo post con parse // create post function const createpost = async () => { if (!postcontent trim() && !postimage) { console error('post must have content or image'); return; } try { // create a new post object const post = parse object extend('post'); const newpost = new post(); // set post content newpost set('content', postcontent); newpost set('author', parse user current()); newpost set('likes', 0); newpost set('likedby', \[]); // if there's an image, upload it if (postimage) { const parsefile = new parse file(postimage name, postimage); await parsefile save(); newpost set('image', parsefile); } // save the post await newpost save(); console log('post created successfully'); return newpost; } catch (error) { console error('error creating post ', error message); throw error; } }; meccanismi chiave di back4app parse object extend('post') riferisce alla classe post in back4app new post() crea una nuova istanza della classe post parsefile save() carica il file nello storage di back4app newpost save() salva l'oggetto post in back4app recupero dei post ecco come recuperare i post da back4app // fetch posts function const fetchposts = async (page = 0, limit = 10) => { try { // create a query for the post class const post = parse object extend('post'); const query = new parse query(post); // include the author object (pointer) query include('author'); // sort by creation date, newest first query descending('createdat'); // pagination query limit(limit); query skip(page limit); // execute the query const results = await query find(); // process the results const posts = results map(post => ({ id post id, content post get('content'), image post get('image') ? post get('image') url() null, likes post get('likes') || 0, likedby post get('likedby') || \[], createdat post get('createdat'), author { id post get('author') id, username post get('author') get('username'), avatar post get('author') get('avatar') ? post get('author') get('avatar') url() null } })); return posts; } catch (error) { console error('error fetching posts ', error); throw error; } }; recupero dei post meccanismi chiave di back4app new parse query(post) crea una query sulla classe post query include('author') esegue un'operazione simile a un join per recuperare oggetti correlati query descending('createdat') ordina i risultati per data di creazione query limit() e query skip() implementa la paginazione post get('image') url() ottiene l'url di un oggetto file di parse implementazione della funzionalità mi piace ecco come implementare i mi piace ai post // like/unlike post function const togglelike = async (postid) => { try { const currentuser = parse user current(); const userid = currentuser id; // get the post object const post = parse object extend('post'); const query = new parse query(post); const post = await query get(postid); // get current likes and likedby array const likedby = post get('likedby') || \[]; const isliked = likedby includes(userid); // update likes count and likedby array if (isliked) { // unlike remove user from likedby and decrement likes post set('likedby', likedby filter(id => id !== userid)); post set('likes', math max((post get('likes') || 1) 1, 0)); } else { // like add user to likedby and increment likes post set('likedby', \[ likedby, userid]); post set('likes', (post get('likes') || 0) + 1); } // save the updated post await post save(); return !isliked; // return new like status } catch (error) { console error('error toggling like ', error); throw error; } }; passo 5 — implementazione dei commenti sui post implementiamo la funzionalità di commento utilizzando back4app creazione dei commenti ecco come aggiungere un commento a un post // add comment function const addcomment = async (postid, commentcontent) => { if (!commentcontent trim()) { console error('comment cannot be empty'); return; } try { // get the post object const post = parse object extend('post'); const postquery = new parse query(post); const post = await postquery get(postid); // create a new comment object const comment = parse object extend('comment'); const comment = new comment(); // set comment data comment set('content', commentcontent); comment set('author', parse user current()); comment set('post', post); // save the comment await comment save(); console log('comment added successfully'); return comment; } catch (error) { console error('error adding comment ', error); throw error; } }; recupero dei commenti per un post ecco come recuperare i commenti per un post specifico // fetch comments function const fetchcomments = async (postid) => { try { // get the post object const post = parse object extend('post'); const postquery = new parse query(post); const post = await postquery get(postid); // create a query for comments const comment = parse object extend('comment'); const query = new parse query(comment); // find comments for this post query equalto('post', post); // include the author information query include('author'); // sort by creation date query ascending('createdat'); // execute the query const results = await query find(); // process the results const comments = results map(comment => ({ id comment id, content comment get('content'), createdat comment get('createdat'), author { id comment get('author') id, username comment get('author') get('username'), avatar comment get('author') get('avatar') ? comment get('author') get('avatar') url() null } })); return comments; } catch (error) { console error('error fetching comments ', error); throw error; } }; passo 6 — implementazione dei profili utente ora implementiamo i profili utente utilizzando back4app recupero dei dati utente ecco come recuperare i dati del profilo utente // fetch user profile function const fetchuserprofile = async (userid) => { try { // create a query for the user class const query = new parse query(parse user); // get the user by id const user = await query get(userid); // get user posts const post = parse object extend('post'); const postsquery = new parse query(post); postsquery equalto('author', user); postsquery include('author'); postsquery descending('createdat'); const posts = await postsquery find(); // process user data const userdata = { id user id, username user get('username'), bio user get('bio') || '', avatar user get('avatar') ? user get('avatar') url() null, followers user get('followers') || 0, following user get('following') || 0, posts posts map(post => ({ id post id, content post get('content'), image post get('image') ? post get('image') url() null, likes post get('likes') || 0, createdat post get('createdat') })) }; return userdata; } catch (error) { console error('error fetching user profile ', error); throw error; } }; aggiornamento del profilo utente ecco come aggiornare il profilo di un utente // update user profile function const updateuserprofile = async (profiledata) => { try { const currentuser = await parse user current(); // update profile fields if (profiledata bio !== undefined) { currentuser set('bio', profiledata bio); } if (profiledata avatarfile) { const parsefile = new parse file('avatar jpg', profiledata avatarfile); await parsefile save(); currentuser set('avatar', parsefile); } // save the updated user await currentuser save(); console log('profile updated successfully'); return currentuser; } catch (error) { console error('error updating profile ', error); throw error; } }; passo 7 — implementazione della messaggistica in tempo reale con livequery ora implementiamo la messaggistica in tempo reale utilizzando la funzione livequery di back4app creazione di conversazioni ecco come creare una nuova conversazione // create conversation function const createconversation = async (participantids) => { try { // ensure current user is included in participants const currentuser = await parse user current(); const allparticipantids = \[ new set(\[currentuser id, participantids])]; // check if conversation already exists const existingconversation = await findexistingconversation(allparticipantids); if (existingconversation) { return existingconversation; } // get user objects for all participants const participantpointers = await promise all( allparticipantids map(async (id) => { const userquery = new parse query(parse user); return await userquery get(id); }) ); // create new conversation const conversation = parse object extend('conversation'); const conversation = new conversation(); conversation set('participants', participantpointers); conversation set('lastmessage', ''); await conversation save(); console log('conversation created successfully'); return conversation; } catch (error) { console error('error creating conversation ', error); throw error; } }; // helper to find existing conversation const findexistingconversation = async (participantids) => { try { const conversation = parse object extend('conversation'); const query = new parse query(conversation); // this is a simplified approach in production you'd need more complex query const results = await query find(); for (const conversation of results) { const participants = conversation get('participants') || \[]; const participantids = participants map(p => p id); // check if arrays have same elements (regardless of order) if (participantids length === participantids length && participantids every(id => participantids includes(id))) { return conversation; } } return null; } catch (error) { console error('error finding existing conversation ', error); return null; } }; invio messaggi ecco come inviare un messaggio in una conversazione // send message function const sendmessage = async (conversationid, messagetext) => { try { const currentuser = parse user current(); // get the conversation const conversation = parse object extend('conversation'); const conversationquery = new parse query(conversation); const conversation = await conversationquery get(conversationid); // create a new message const message = parse object extend('message'); const message = new message(); message set('text', messagetext); message set('sender', currentuser); message set('conversation', conversation); message set('read', false); await message save(); // update conversation with last message conversation set('lastmessage', messagetext); await conversation save(); console log('message sent successfully'); return message; } catch (error) { console error('error sending message ', error); throw error; } }; impostazione di livequery per i messaggi ecco come iscriversi agli aggiornamenti dei messaggi in tempo reale // subscribe to messages function const subscribetomessages = async (conversationid, onnewmessage) => { try { // create a query for messages in this conversation const message = parse object extend('message'); const query = new parse query(message); // get the conversation pointer const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = conversationid; // set up query constraints query equalto('conversation', conversationpointer); query include('sender'); // subscribe to the query const subscription = await query subscribe(); // listen for create events (new messages) subscription on('create', (message) => { // process the message const newmessage = { id message id, text message get('text'), createdat message get('createdat'), sender { id message get('sender') id, username message get('sender') get('username'), avatar message get('sender') get('avatar') ? message get('sender') get('avatar') url() null }, read message get('read') }; // call the callback with the new message onnewmessage(newmessage); // mark the message as read if from another user if (message get('sender') id !== parse user current() id) { markmessageasread(message); } }); return subscription; } catch (error) { console error('error subscribing to messages ', error); throw error; } }; // helper to mark message as read const markmessageasread = async (message) => { try { message set('read', true); await message save(); } catch (error) { console error('error marking message as read ', error); } }; implementazione degli indicatori di digitazione ecco come implementare gli indicatori di digitazione con livequery // update typing status function const updatetypingstatus = async (conversationid, istyping) => { try { const currentuser = parse user current(); // get the conversation pointer const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = conversationid; // check if typing status exists const typingstatus = parse object extend('typingstatus'); const query = new parse query(typingstatus); query equalto('conversation', conversationpointer); query equalto('user', currentuser); let typingstatus = await query first(); if (typingstatus) { // update existing status typingstatus set('istyping', istyping); } else { // create new status typingstatus = new typingstatus(); typingstatus set('conversation', conversationpointer); typingstatus set('user', currentuser); typingstatus set('istyping', istyping); } await typingstatus save(); } catch (error) { console error('error updating typing status ', error); } }; // subscribe to typing status function const subscribetotypingstatus = async (conversationid, ontypingstatuschange) => { try { // create a query for typing status in this conversation const typingstatus = parse object extend('typingstatus'); const query = new parse query(typingstatus); // get the conversation pointer const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = conversationid; // set up query constraints query equalto('conversation', conversationpointer); query include('user'); // subscribe to the query const subscription = await query subscribe(); // listen for update events subscription on('update', (typingstatus) => { const user = typingstatus get('user'); const istyping = typingstatus get('istyping'); // call the callback with typing status ontypingstatuschange({ userid user id, username user get('username'), istyping }); }); // also listen for create events subscription on('create', (typingstatus) => { const user = typingstatus get('user'); const istyping = typingstatus get('istyping'); // call the callback with typing status ontypingstatuschange({ userid user id, username user get('username'), istyping }); }); return subscription; } catch (error) { console error('error subscribing to typing status ', error); throw error; } }; passo 8 — implementazione della funzionalità di ricerca implementiamo la funzionalità di ricerca utilizzando il sistema di query di back4app ricerca di utenti ecco come cercare utenti // search users function const searchusers = async (query, limit = 20) => { try { // create a query on the user class const userquery = new parse query(parse user); // search by username (case insensitive) userquery matches('username', new regexp(query, 'i')); // limit results to improve performance userquery limit(limit); // execute the query const users = await userquery find(); // process the results const userresults = users map(user => ({ id user id, username user get('username'), avatar user get('avatar') ? user get('avatar') url() null, bio user get('bio') || '' })); return userresults; } catch (error) { console error('error searching users ', error); throw error; } }; \### searching for posts here's how to search for posts by content ```javascript // search posts function const searchposts = async (query, limit = 20) => { try { // create a query on the post class const post = parse object extend('post'); const postquery = new parse query(post); // search for posts with content containing the query string postquery matches('content', new regexp(query, 'i')); // include the author information postquery include('author'); // sort by creation date (newest first) postquery descending('createdat'); // limit results postquery limit(limit); // execute the query const posts = await postquery find(); // process the results const postresults = posts map(post => ({ id post id, content post get('content'), image post get('image') ? post get('image') url() null, likes post get('likes') || 0, createdat post get('createdat'), author { id post get('author') id, username post get('author') get('username'), avatar post get('author') get('avatar') ? post get('author') get('avatar') url() null } })); return postresults; } catch (error) { console error('error searching posts ', error); throw error; } }; ricerca di hashtag ecco come cercare post con hashtag specifici // search hashtags function const searchhashtags = async (tag, limit = 20) => { try { // remove # if present at the beginning const hashtagquery = tag startswith('#') ? tag substring(1) tag; // create a query on the post class const post = parse object extend('post'); const postquery = new parse query(post); // search for posts with content containing the hashtag // using word boundaries to find actual hashtags postquery matches('content', new regexp(`#${hashtagquery}\\\b`, 'i')); // include the author information postquery include('author'); // sort by creation date (newest first) postquery descending('createdat'); // limit results postquery limit(limit); // execute the query const posts = await postquery find(); // process the results const hashtagresults = posts map(post => ({ id post id, content post get('content'), image post get('image') ? post get('image') url() null, likes post get('likes') || 0, createdat post get('createdat'), author { id post get('author') id, username post get('author') get('username'), avatar post get('author') get('avatar') ? post get('author') get('avatar') url() null } })); return hashtagresults; } catch (error) { console error('error searching hashtags ', error); throw error; } }; passo 9 — implementazione delle funzionalità avanzate di back4app esploriamo alcune funzionalità avanzate di back4app che possono migliorare la tua applicazione di social network funzioni cloud back4app ti consente di implementare logica lato server utilizzando funzioni cloud queste sono funzioni javascript che vengono eseguite sul server e possono essere chiamate dalla tua app client ecco un esempio di una funzione cloud per il tracciamento delle notifiche dei commenti // in your back4app cloud code section parse cloud aftersave("comment", async (request) => { // only run for new comments, not updates if (request original) return; const comment = request object; const post = comment get("post"); const commenter = request user; // skip if user is commenting on their own post const postquery = new parse query("post"); const fullpost = await postquery get(post id, { usemasterkey true }); const postauthor = fullpost get("author"); if (postauthor id === commenter id) return; // create a notification const notification = parse object extend("notification"); const notification = new notification(); notification set("type", "comment"); notification set("fromuser", commenter); notification set("touser", postauthor); notification set("post", post); notification set("read", false); await notification save(null, { usemasterkey true }); }); per implementare questo vai al tuo dashboard di back4app naviga su "cloud code" > "funzioni cloud" crea una nuova funzione con il codice sopra distribuisci la funzione cloud code per ricerca avanzata per funzionalità di ricerca più complesse, puoi creare una cloud function // in your back4app cloud code section parse cloud define("advancedsearch", async (request) => { const { query, type, limit = 20 } = request params; if (!query) { throw new error("search query is required"); } let results = \[]; switch (type) { case 'users' const userquery = new parse query(parse user); userquery matches('username', new regexp(query, 'i')); userquery limit(limit); results = await userquery find({ usemasterkey true }); break; case 'posts' const post = parse object extend('post'); const postquery = new parse query(post); postquery matches('content', new regexp(query, 'i')); postquery include('author'); postquery limit(limit); results = await postquery find({ usemasterkey true }); break; default throw new error("invalid search type"); } return results; }); per chiamare questa funzione dal tuo client // call the advanced search cloud function const calladvancedsearch = async (query, type, limit = 20) => { try { const results = await parse cloud run('advancedsearch', { query, type, limit }); return results; } catch (error) { console error('error calling advanced search ', error); throw error; } }; implementazione di job in background per compiti ricorrenti come il calcolo dei temi di tendenza, puoi utilizzare i job in background // in your back4app cloud code section parse cloud job("calculatetrendingtopics", async () => { // get posts from the last 7 days const post = parse object extend("post"); const query = new parse query(post); const oneweekago = new date(); oneweekago setdate(oneweekago getdate() 7); query greaterthan('createdat', oneweekago); // limit to a reasonable number for analysis query limit(1000); const posts = await query find({ usemasterkey true }); // extract hashtags and count occurrences const hashtagcounts = {}; posts foreach(post => { const content = post get('content') || ''; const hashtags = content match(/#(\w+)/g) || \[]; hashtags foreach(hashtag => { const tag = hashtag tolowercase(); hashtagcounts\[tag] = (hashtagcounts\[tag] || 0) + 1; }); }); // convert to array and sort by count const trendingarray = object entries(hashtagcounts) map((\[hashtag, count]) => ({ hashtag, count })) sort((a, b) => b count a count) slice(0, 10); // get top 10 // save to a trendingtopics class const trendingtopics = parse object extend("trendingtopics"); const trending = new trendingtopics(); trending set("topics", trendingarray); trending set("calculatedat", new date()); await trending save(null, { usemasterkey true }); return "trending topics calculated successfully"; }); per impostare questo lavoro vai al tuo dashboard di back4app naviga su "cloud code" > "background jobs" crea un nuovo lavoro con il codice sopra programma per eseguirlo quotidianamente o settimanalmente utilizzando i parse server hooks back4app ti consente di implementare hook lato server che vengono eseguiti automaticamente prima o dopo determinate operazioni questi sono utili per la convalida dei dati, la modifica o l'attivazione di effetti collaterali // beforesave hook to sanitize post content parse cloud beforesave("post", async (request) => { const post = request object; let content = post get("content"); // sanitize content (example remove profanity) const profanitylist = \["badword1", "badword2", "badword3"]; profanitylist foreach(word => { const regex = new regexp(word, "gi"); content = content replace(regex, " "); }); // update the content post set("content", content); }); // afterdelete hook to clean up related data parse cloud afterdelete("post", async (request) => { const post = request object; const postid = post id; // delete all comments associated with this post const comment = parse object extend("comment"); const query = new parse query(comment); query equalto("post", post); const comments = await query find({ usemasterkey true }); await parse object destroyall(comments, { usemasterkey true }); console log(`deleted ${comments length} comments for post ${postid}`); }); implementazione delle notifiche push back4app fornisce un robusto sistema di notifiche push che ti consente di inviare notifiche ai dispositivi dei tuoi utenti ecco come implementare le notifiche push per prima cosa, imposta una configurazione push nel tuo dashboard di back4app vai su "impostazioni app" > "push" configura le tue credenziali ios e/o android invia una notifica push quando un utente riceve un nuovo messaggio // in your cloud code parse cloud aftersave("message", async (request) => { const message = request object; const conversation = message get("conversation"); const sender = message get("sender"); // get the conversation to find recipients const conversationquery = new parse query("conversation"); const fullconversation = await conversationquery get(conversation id, { usemasterkey true }); // get all participants const participants = fullconversation get("participants") || \[]; // send notification to all participants except the sender for (const participant of participants) { if (participant id !== sender id) { // create a query for this user's installations const pushquery = new parse query(parse installation); pushquery equalto("user", participant); // send the push notification await parse push send({ where pushquery, data { alert `new message from ${sender get("username")}`, sound "default", badge "increment", sender sender id, messageid message id, conversationid conversation id } }, { usemasterkey true }); } } }); utilizzo del controllo degli accessi basato sui ruoli back4app fornisce un sistema di controllo degli accessi basato sui ruoli che consente di gestire le autorizzazioni a un livello più granulare // create an admin role const createadminrole = async (adminuser) => { try { // create a new role const adminrole = new parse role("administrator", new parse acl()); // set initial users of this role adminrole getusers() add(adminuser); // save the role await adminrole save(null, { usemasterkey true }); console log("admin role created successfully"); return adminrole; } catch (error) { console error("error creating admin role ", error); throw error; } }; // set permissions for posts to be moderated by admins const setpostmoderatorpermissions = async () => { try { // get the admin role const rolequery = new parse query(parse role); rolequery equalto("name", "administrator"); const adminrole = await rolequery first({ usemasterkey true }); // set class level permissions const schema = new parse schema("post"); // add class level permissions for admin role await schema setclp({ get { " " true }, find { " " true }, create { " " true }, update { "role\ administrator" true, "" true }, // creator and admins can update delete { "role\ administrator" true, "" true }, // creator and admins can delete addfield { "role\ administrator" true } }); await schema update(); console log("admin permissions for post class set successfully"); } catch (error) { console error("error setting admin permissions ", error); throw error; } }; implementazione dei webhook back4app ti consente di impostare webhook per integrarti con servizi esterni // example cloud function that calls an external webhook parse cloud aftersave("post", async (request) => { const post = request object; // only trigger for new posts if (request original) return; try { // get author information const author = post get("author"); await author fetch({ usemasterkey true }); // prepare data for webhook const webhookdata = { postid post id, content post get("content"), authorname author get("username"), createdat post get("createdat") }; // call external webhook (example notify a content moderation service) const response = await parse cloud httprequest({ method 'post', url 'https //your webhook url com/new post', headers { 'content type' 'application/json' }, body webhookdata }); console log("webhook notification sent successfully ", response data); } catch (error) { console error("error sending webhook notification ", error); } }); passo 10 — ottimizzazione delle prestazioni di back4app man mano che la tua rete sociale cresce, dovrai ottimizzare il tuo backend di back4app per prestazioni e scalabilità questa sezione copre strategie essenziali per garantire che la tua applicazione rimanga veloce e reattiva anche con l'espansione della tua base utenti ottimizzazione del database un design e una query del database efficienti sono cruciali per le prestazioni dell'applicazione creazione di indici gli indici migliorano notevolmente le prestazioni delle query sui campi frequentemente cercati vai al tuo dashboard di back4app naviga su "database browser" > seleziona una classe (es post) clicca sulla scheda "indici" crea indici per i campi frequentemente cercati // example creating indexes programmatically const createpostindexes = async () => { try { const schema = new parse schema('post'); // add an index on the author field await schema addindex('author index', { author 1 }); // add an index on createdat for timeline queries await schema addindex('createdat index', { createdat 1 }); // add a compound index for author + createdat await schema addindex('author date index', { author 1, createdat 1 }); await schema update(); console log('indexes created successfully'); } catch (error) { console error('error creating indexes ', error); } }; campi chiave da indicizzare autore nella classe post per query specifiche più veloci createdat per un caricamento temporale più veloce nome utente nella classe utente per ricerche utente più veloci partecipanti nella classe conversazione per un filtraggio dei messaggi più veloce ottimizzazione delle query ottimizza le tue query per ridurre il carico del server e il tempo di risposta // bad fetches all fields and doesn't use limit const fetchuserposts = async (userid) => { const query = new parse query('post'); query equalto('author', userid); const results = await query find(); return results; }; // good only fetches needed fields and uses limit const fetchuserposts = async (userid, page = 0, limit = 20) => { const post = parse object extend('post'); const query = new parse query(post); // get user pointer const userpointer = { type 'pointer', classname ' user', objectid userid }; // only get posts for this user query equalto('author', userpointer); // only select fields we need query select('content', 'image', 'likes', 'createdat'); // sort by date, newest first query descending('createdat'); // implement pagination query limit(limit); query skip(page limit); const results = await query find(); return results; }; operazioni in batch per operazioni che coinvolgono più oggetti, utilizza operazioni in batch per ridurre le chiamate api // update multiple posts in a single request const updatemultipleposts = async (postids, updatedata) => { try { const post = parse object extend('post'); const posts = postids map(id => { const post = new post(); post id = id; return post; }); // set the same update data on all posts posts foreach(post => { object entries(updatedata) foreach((\[key, value]) => { post set(key, value); }); }); // save all posts in a single request await parse object saveall(posts); console log('all posts updated successfully'); } catch (error) { console error('error updating posts ', error); throw error; } }; // delete multiple comments in a single request const deletemultiplecomments = async (commentids) => { try { const comment = parse object extend('comment'); const comments = commentids map(id => { const comment = new comment(); comment id = id; return comment; }); // delete all comments in a single request await parse object destroyall(comments); console log('all comments deleted successfully'); } catch (error) { console error('error deleting comments ', error); throw error; } }; implementazione della cache implementa la cache lato client per i dati frequentemente accessibili per ridurre le chiamate api // caching user profiles const userprofilecache = new map(); const cache expiry = 10 60 1000; // 10 minutes in milliseconds const getuserprofile = async (userid, forcerefresh = false) => { // check if we have a valid cache entry const now = date now(); const cacheentry = userprofilecache get(userid); if (!forcerefresh && cacheentry && (now cacheentry timestamp < cache expiry)) { console log('using cached user profile'); return cacheentry data; } try { // fetch from back4app const query = new parse query(parse user); const user = await query get(userid); // process user data const userdata = { id user id, username user get('username'), bio user get('bio') || '', avatar user get('avatar') ? user get('avatar') url() null, followers user get('followers') || 0, following user get('following') || 0 }; // store in cache with timestamp userprofilecache set(userid, { data userdata, timestamp now }); return userdata; } catch (error) { console error('error fetching user profile ', error); // return cached data even if expired in case of error if (cacheentry) { console log('using expired cache due to error'); return cacheentry data; } throw error; } }; // clear cache for a user when their profile is updated const invalidateusercache = (userid) => { userprofilecache delete(userid); }; utilizzare livequery in modo efficiente livequery è potente per le funzionalità in tempo reale ma dovrebbe essere utilizzato in modo efficiente per evitare problemi di prestazioni // efficient livequery usage const setupefficientlivequery = async (conversationid) => { try { // only subscribe to messages in the active conversation if (!conversationid) return null; // create a focused query const message = parse object extend('message'); const query = new parse query(message); // get the conversation pointer const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = conversationid; // only get messages for this conversation query equalto('conversation', conversationpointer); // only include necessary fields query select('text', 'sender', 'createdat'); // limit initial results query limit(50); query descending('createdat'); // create subscription const subscription = await query subscribe(); subscription on('create', (message) => { // handle new message console log('new message ', message get('text')); // update ui with new message }); // unsubscribe when switching conversations return subscription; } catch (error) { console error('error setting up livequery ', error); return null; } }; // always unsubscribe when done const cleanuplivequery = (subscription) => { if (subscription) { subscription unsubscribe(); } }; migliori pratiche per livequery iscriviti solo ai dati che necessitano di aggiornamenti in tempo reale limita i campi che richiedi con select() disiscriviti sempre quando i dati non sono più necessari usa vincoli per restringere l'ambito delle iscrizioni considera di combinare livequery con query regolari per il caricamento iniziale dei dati ottimizzazione della gestione dei file una gestione efficiente dei file è cruciale per un social network con caricamenti di immagini // resize images before upload to reduce storage and bandwidth const uploadresizedimage = async (originalfile, maxwidth = 1200, maxheight = 1200) => { return new promise((resolve, reject) => { try { const reader = new filereader(); reader onload = (event) => { const img = new image(); img onload = () => { // calculate new dimensions let width = img width; let height = img height; if (width > maxwidth) { height = math round(height (maxwidth / width)); width = maxwidth; } if (height > maxheight) { width = math round(width (maxheight / height)); height = maxheight; } // create canvas for resizing const canvas = document createelement('canvas'); canvas width = width; canvas height = height; // draw resized image const ctx = canvas getcontext('2d'); ctx drawimage(img, 0, 0, width, height); // convert to blob canvas toblob(async (blob) => { const resizedfile = new file(\[blob], originalfile name, { type originalfile type, lastmodified date now() }); // upload to back4app const parsefile = new parse file(resizedfile name, resizedfile); await parsefile save(); resolve(parsefile); }, originalfile type, 0 8); // 0 8 quality for jpeg }; img src = event target result; }; reader readasdataurl(originalfile); } catch (error) { reject(error); } }); }; // use thumbnails for preview images const createthumbnailversion = async (originalfile, thumbnailwidth = 200) => { // similar to above but creating a smaller thumbnail // // return both original and thumbnail return { original originalparsefile, thumbnail thumbnailparsefile }; }; monitorare la tua app back4app back4app fornisce diversi strumenti per monitorare le prestazioni della tua applicazione dashboard analytics fornisce statistiche di utilizzo a livello elevato monitora le richieste api, l'uso dello storage e le operazioni sui file identifica i modelli di utilizzo e i picchi di traffico log forniscono informazioni dettagliate sulle operazioni esamina i log del server per errori e problemi di prestazioni filtra i log per tipo per isolare i problemi metriche di prestazione monitora i tempi di risposta e la salute del sistema monitora le prestazioni delle query identifica le operazioni lente configura avvisi per essere notificato di potenziali problemi vai su "impostazioni app" > "avvisi" nel tuo dashboard di back4app imposta avvisi per alto utilizzo dell'api (in avvicinamento ai limiti del tuo piano) picchi nel tasso di errore (indicando problemi dell'applicazione) tempo di inattività del server (che influisce su tutti gli utenti) utilizzo dello spazio di archiviazione (in avvicinamento alla capacità) // implementing custom logging for performance monitoring const logperformance = async (operation, starttime) => { const duration = date now() starttime; // log to back4app const performancelog = parse object extend('performancelog'); const log = new performancelog(); log set('operation', operation); log set('duration', duration); log set('user', parse user current() ? parse user current() id 'anonymous'); log set('timestamp', new date()); await log save(null, { usemasterkey true }); // log locally too console log(`performance ${operation} took ${duration}ms`); }; // example usage const fetchtimelineposts = async () => { const starttime = date now(); try { // query code here // // calculate and log performance await logperformance('fetchtimelineposts', starttime); return results; } catch (error) { console error('error ', error); throw error; } }; strategie di scalabilità man mano che la tua applicazione cresce, considera queste strategie di scalabilità aggiorna il tuo piano back4app passa a un livello superiore man mano che la tua base utenti si espande monitora l'uso e aggiorna prima di raggiungere i limiti implementa lo sharding per collezioni grandi dividi i dati tra più classi per dataset molto grandi ad esempio, dividi i messaggi per anno o mese // example of sharded messages implementation const sendshardedmessage = async (conversationid, text, sender) => { try { // determine which shard to use (e g , by current month) const now = new date(); const shardname = `message ${now\ getfullyear()} ${now\ getmonth() + 1}`; // create dynamic class reference const messageshard = parse object extend(shardname); const message = new messageshard(); // create a pointer to the conversation const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = conversationid; // set message data message set('conversation', conversationpointer); message set('text', text); message set('sender', sender); // save to appropriate shard await message save(); return message; } catch (error) { console error('error sending sharded message ', error); throw error; } }; // fetch messages across shards const fetchshardedmessages = async (conversationid, limit = 50) => { try { // get list of all message shards const shards = await getmessageshardnames(); // create a query for each shard const queries = shards map(shardname => { const messageshard = parse object extend(shardname); const query = new parse query(messageshard); // create a pointer to the conversation const conversation = parse object extend('conversation'); const conversationpointer = new conversation(); conversationpointer id = conversationid; query equalto('conversation', conversationpointer); return query; }); // combine queries const mainquery = parse query or( queries); mainquery descending('createdat'); mainquery limit(limit); return await mainquery find(); } catch (error) { console error('error fetching sharded messages ', error); throw error; } }; implementare il server di caching utilizzare redis o altre soluzioni di caching per dati frequentemente accessibili implementare tramite cloud code e servizi esterni utilizzare le reti di distribuzione dei contenuti (cdn) configurare la cdn per una consegna più rapida dei file particolarmente importante per immagini e file multimediali ottimizzazioni della sicurezza la sicurezza e le prestazioni sono strettamente correlate queste ottimizzazioni migliorano entrambe implementa le autorizzazioni dei puntatori utilizza le autorizzazioni dei puntatori per limitare l'accesso agli oggetti correlati questo consente query più efficienti senza compromettere la sicurezza // set up pointer permissions const setuppointerpermissions = async () => { try { // get the message class schema const schema = new parse schema('message'); // add pointer permissions only conversation participants can access messages const pointerpermissions = { 'conversation' { 'read' { 'participantsfield' 'participants' } } }; // update the schema with pointer permissions await schema addpointerpermissions(pointerpermissions); await schema update(); console log('pointer permissions set successfully'); } catch (error) { console error('error setting pointer permissions ', error); } }; utilizza le acl di parse in modo efficiente le acl forniscono sicurezza ma possono influire sulle prestazioni se utilizzate eccessivamente considera di utilizzare le autorizzazioni a livello di classe per i casi comuni e le acl per le eccezioni // efficient acl usage set default acl parse setdefaultacl(new parse acl({ publicreadaccess true }), true); // only use specific acls for private content const createprivatepost = async (content, image) => { const currentuser = parse user current(); // create a new private post const post = parse object extend('post'); const post = new post(); // set post data post set('content', content); post set('author', currentuser); if (image) { const parsefile = new parse file(image name, image); await parsefile save(); post set('image', parsefile); } // create private acl const privateacl = new parse acl(currentuser); // only the creator can read and write privateacl setreadaccess(currentuser id, true); privateacl setwriteaccess(currentuser id, true); // set the acl post setacl(privateacl); // save the post await post save(); return post; }; ottimizzazione del server back4app ottimizza la configurazione del tuo server parse in back4app configura i parametri del server vai su "impostazioni app" > "impostazioni server" regola le impostazioni di timeout per operazioni lunghe configura i limiti massimi delle richieste imposta il rate limiting implementa il rate limiting per prevenire abusi e garantire un uso equo configura tramite cloud code come mostrato in precedenza implementando queste strategie di ottimizzazione delle prestazioni, la tua applicazione di social network sarà ben posizionata per gestire la crescita e mantenere prestazioni eccellenti, anche con l'espansione della tua base utenti ricorda di monitorare continuamente le prestazioni della tua applicazione e di apportare miglioramenti incrementali secondo necessità conclusione in questo tutorial, hai imparato come costruire un'applicazione di social network completa utilizzando back4app come servizio backend hai implementato funzionalità fondamentali come autenticazione utente e gestione del profilo creazione di post e interazioni sociali messaggistica in tempo reale con livequery funzionalità di ricerca funzionalità avanzate come cloud functions e background jobs il parse server di back4app fornisce una soluzione backend potente e scalabile che ti consente di concentrarti sulla creazione di ottime esperienze utente senza preoccuparti di infrastrutture server complesse prossimi passi per migliorare ulteriormente la tua applicazione di social network, considera implementare notifiche push utilizzando il servizio push di back4app aggiungere analisi per monitorare l'engagement degli utenti impostare opzioni di archiviazione file per file multimediali più grandi implementare la moderazione dei contenuti utilizzando cloud functions creare un'app mobile utilizzando react native con lo stesso backend di back4app sfruttando le funzionalità di back4app e seguendo le strategie di ottimizzazione delineate in questo tutorial, puoi costruire un social network che scala per gestire migliaia di utenti mantenendo alte prestazioni risorse aggiuntive per continuare ad ampliare le tue conoscenze su back4app, ecco alcune risorse preziose documentazione di back4app documentazione di back4app https //www back4app com/docs/get started/welcome guida javascript di parse https //docs parseplatform org/js/guide/ canale youtube di back4app https //www youtube com/c/back4app parse server e livequery documentazione di parse server https //docs parseplatform org/parse server/guide/ guida a livequery https //docs parseplatform org/parse server/guide/#live queries sicurezza e ottimizzazione guida ai permessi a livello di classe https //docs parseplatform org/rest/guide/#class level permissions guida alla sicurezza acl https //docs parseplatform org/js/guide/#security ottimizzazione delle prestazioni https //docs parseplatform org/js/guide/#performance funzionalità avanzate guida al cloud code https //docs parseplatform org/cloudcode/guide/ lavori in background https //docs parseplatform org/cloudcode/guide/#cloud jobs notifiche push https //docs parseplatform org/js/guide/#push notifications ricorda che costruire una rete sociale di successo è un processo iterativo inizia con una base solida (che ora hai), raccogli feedback dagli utenti e migliora continuamente la tua applicazione in base ai modelli di utilizzo nel mondo reale speriamo che questo tutorial ti abbia fornito le conoscenze e la fiducia per costruire applicazioni straordinarie con back4app buon coding!