Quickstart Guide
Get the Horse Trust platform running locally in just a few minutes. This guide will walk you through cloning the repository, installing dependencies, configuring environment variables, and starting both the client and server applications.
Prerequisites
Before you begin, ensure you have the following installed:
Node.js Version 24.13.0 or higher
Git Version 2.43.0 or higher
MongoDB MongoDB Atlas account or local MongoDB instance
npm Comes bundled with Node.js
Installation
Clone the Repository
Clone the Horse Trust repository to your local machine: git clone [email protected] :No-Country-simulation/S02-26-Equipo-33-Web-App.git
cd S02-26-Equipo-33-Web-App
The repository follows a monorepo structure with separate client and server directories.
Set Up the Backend Server
Navigate to the server directory and install dependencies: Create a .env file in the server directory based on .env.example: # ================================
# 🌍 SERVER DATABASE CONNECTION 🌍
# ================================
PORT = 8031
NODE_ENV = development
MONGO_URI = mongodb+srv://username:[email protected] /horsetrust? retryWrites = true & w = majority
# ================================
# JWT Configuration
# ================================
JWT_SECRET = your-super-secret-jwt-key-change-this-in-production
JWT_EXPIRES_IN = 10d
BCRYPT_SALT_ROUNDS = 12
# ================================
# CORS Configuration
# ================================
CORS_ORIGINS = http://localhost:8030,http://localhost:3000
# ================================
# Rate Limiting (Optional)
# ================================
RATE_LIMIT_WINDOW_MS = 900000
RATE_LIMIT_MAX = 100
Replace MONGO_URI with your actual MongoDB connection string. You can get one from MongoDB Atlas for free. The JWT_SECRET should be a long, random string. In production, use a cryptographically secure random value.
Start the Server Run the development server: The server will start on http://localhost:8031 (or the port specified in your .env file). Test the Server Verify the server is running by testing the health endpoint: curl http://localhost:8031/health
You should receive a response like: {
"success" : true ,
"message" : "Horse Portal API is running" ,
"env" : "development"
}
Set Up the Frontend Client
Open a new terminal window and navigate to the client directory: Create a .env.local file in the client directory: # ==========================================
# VARIABLES DE ENTORNO - HORSETRUST (FRONTEND)
# ==========================================
# URL base de la API de backend
NEXT_PUBLIC_API_URL = http://localhost:8031/api
# Cloudinary Configuration (for image uploads)
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME = di2agiylz
NEXT_PUBLIC_CLOUDINARY_UPLOAD_PRESET = horse_trust_uploads
The NEXT_PUBLIC_API_URL should point to your backend server. Make sure the port matches your server configuration.
Start the Client Run the Next.js development server: The client will start on http://localhost:8030.
Access the Application
Open your browser and navigate to: You should see the Horse Trust landing page with:
Hero section introducing the platform
Featured horses section
Security features section
Navigation header and footer
Development Workflow
Running Both Services
For development, you’ll need two terminal windows:
Terminal 1 - Backend
Terminal 2 - Frontend
Available Scripts
Backend Scripts
{
"scripts" : {
"dev" : "nodemon" , // Start development server with hot reload
"start" : "node dist/index.js" // Start production server
}
}
Frontend Scripts
{
"scripts" : {
"dev" : "next dev -p 8030" , // Start development server on port 8030
"build" : "next build" , // Build for production
"start" : "next start -p 8030" , // Start production server
"lint" : "eslint" // Run ESLint
}
}
Authentication Flow
Register a New User
Use the registration action to create a new account:
client/app/actions/auth.ts
import { apiFetch } from '../utils/apiFetch' ;
import { cookies } from 'next/headers' ;
export async function registerUser ( userData : any ) {
const res = await apiFetch ( '/auth/register' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ( userData ),
});
const data = await res . json ();
if ( ! res . ok ) {
throw new Error ( data . message || 'Error al registrar el usuario' );
}
// Store JWT token in HTTP-only cookie
const cookieStore = await cookies ();
cookieStore . set ( 'horse_trust_token' , data . token , {
httpOnly: true ,
secure: process . env . NODE_ENV === 'production' ,
maxAge: 60 * 60 * 24 * 7 , // 7 days
path: '/' ,
});
return { success: true , data };
}
Login Flow
export async function loginUser ( email : string , password : string ) {
const res = await apiFetch ( '/auth/login' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({ email , password }),
});
const data = await res . json ();
if ( ! res . ok ) {
throw new Error ( data . error || 'Error al validar credenciales' );
}
const cookieStore = await cookies ();
cookieStore . set ( 'horse_trust_token' , data . token , {
httpOnly: true ,
secure: process . env . NODE_ENV === 'production' ,
maxAge: 60 * 60 * 24 * 7 ,
path: '/' ,
});
return { success: true , data };
}
Creating Your First Horse Listing
Once logged in as a seller, you can create horse listings:
client/app/actions/horses.ts
import { apiFetch } from '../utils/apiFetch' ;
import { cookies } from 'next/headers' ;
import { revalidatePath } from 'next/cache' ;
export async function createHorse ( horseData : any ) {
const cookieStore = await cookies ();
const token = cookieStore . get ( 'horse_trust_token' )?. value ;
if ( ! token ) {
return { success: false , error: "No hay una sesión activa" };
}
const res = await apiFetch ( '/horses' , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
'Authorization' : `Bearer ${ token } `
},
body: JSON . stringify ( horseData ),
});
const data = await res . json ();
if ( ! res . ok ) {
return { success: false , error: data . error || "Error al publicar el caballo" };
}
// Revalidate relevant pages
revalidatePath ( '/marketplace' );
revalidatePath ( '/dashboard' );
return { success: true , data };
}
Horse Data Structure
const horseData = {
name: "Thunder" ,
age: 5 ,
breed: "Thoroughbred" ,
discipline: "Show Jumping" ,
pedigree: "Sire: Lightning | Dam: Storm" ,
location: {
country: "Argentina" ,
region: "Buenos Aires" ,
city: "La Plata" ,
coordinates: { lat: - 34.9214 , lng: - 57.9544 }
},
price: 50000 ,
currency: "USD" ,
photos: [
{ url: "https://..." , caption: "Front view" , is_cover: true },
{ url: "https://..." , caption: "Side view" },
{ url: "https://..." , caption: "Action shot" }
],
videos: [
{
url: "https://youtube.com/watch?v=..." ,
video_type: "training" ,
title: "Training Session" ,
recorded_at: "2026-03-01T00:00:00Z"
}
],
status: "active"
};
At least 3 photos are required for each horse listing. The platform validates this at the database level.
Real-time Chat Setup
The platform uses Socket.io for real-time messaging between buyers and sellers:
import { Server as SocketServer } from "socket.io" ;
import jwt from "jsonwebtoken" ;
const io = new SocketServer ( httpServer , {
cors: {
origin: process . env . CORS_ORIGINS . split ( "," ),
credentials: true ,
},
});
// JWT authentication for socket connections
io . use (( socket , next ) => {
const token = socket . handshake . auth ?. token ;
if ( ! token ) {
return next ( new Error ( "Authentication error: no token" ));
}
try {
const decoded = jwt . verify ( token , process . env . JWT_SECRET );
socket . user = decoded ;
next ();
} catch {
next ( new Error ( "Authentication error: invalid token" ));
}
});
io . on ( "connection" , ( socket ) => {
// Join user-specific room
socket . join ( `user: ${ socket . user . userId } ` );
// Join conversation room
socket . on ( "join_conversation" , ( conversationId ) => {
socket . join ( `conv: ${ conversationId } ` );
});
// Send message
socket . on ( "send_message" , async ( data , ack ) => {
// Message handling logic...
});
});
Troubleshooting
Common Issues
MongoDB Connection Failed
Verify your MONGO_URI is correct
Check if your IP address is whitelisted in MongoDB Atlas
Ensure network connectivity to MongoDB
Check MongoDB Atlas cluster status
Ensure CORS_ORIGINS in server .env includes your client URL
Check that both frontend and backend are running
Verify the NEXT_PUBLIC_API_URL matches your backend URL
Change the port in your .env files:
Server: Update PORT in server/.env
Client: Update the -p flag in client/package.json scripts
Ensure JWT_SECRET is set in server .env
Check token expiration (default 10 days)
Clear browser cookies and re-login
Database Auto-Reconnect
The platform includes an automatic database reconnection feature:
client/app/utils/apiFetch.ts
export async function apiFetch ( endpoint : string , options : RequestInit = {}) {
const apiUrl = process . env . NEXT_PUBLIC_API_URL ;
const url = ` ${ apiUrl }${ endpoint } ` ;
try {
let res = await fetch ( url , options );
// Auto-retry with database reconnection on 5xx errors
if ( ! res . ok && res . status >= 500 ) {
console . log ( `API failed. Attempting to wake Oracle...` );
const reconRes = await fetch ( ` ${ apiUrl } /health/reconnect` , {
method: 'POST'
});
if ( reconRes . ok ) {
console . log ( `DB reconnected. Retrying request...` );
res = await fetch ( url , options );
}
}
return res ;
} catch ( error ) {
console . error ( `Network error. Attempting reconnect...` , error );
await fetch ( ` ${ apiUrl } /health/reconnect` , { method: 'POST' });
return await fetch ( url , options );
}
}
The /health/reconnect endpoint called by the frontend is referenced in the client code but not yet implemented in the backend API. The frontend includes this code for future database reconnection functionality.
Next Steps
Architecture Overview Learn about the system architecture and how components interact
API Reference Explore the complete API documentation
Contributing Learn how to contribute to the Horse Trust project
Deployment Deploy Horse Trust to production
For production deployment, remember to:
Use strong, unique values for JWT_SECRET
Set NODE_ENV=production
Configure proper CORS origins
Use SSL/TLS certificates
Set up proper MongoDB authentication
Enable security features (Helmet, rate limiting)