Skip to main content

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

1

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.
2

Set Up the Backend Server

Navigate to the server directory and install dependencies:
cd server
npm install

Configure Server Environment Variables

Create a .env file in the server directory based on .env.example:
server/.env
# ================================
# 🌍 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:
npm run dev
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"
}
3

Set Up the Frontend Client

Open a new terminal window and navigate to the client directory:
cd client
npm install

Configure Client Environment Variables

Create a .env.local file in the client directory:
client/.env.local
# ==========================================
# 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:
npm run dev
The client will start on http://localhost:8030.
4

Access the Application

Open your browser and navigate to:
http://localhost:8030
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:
cd server
npm run dev

Available Scripts

Backend Scripts

server/package.json
{
  "scripts": {
    "dev": "nodemon",           // Start development server with hot reload
    "start": "node dist/index.js" // Start production server
  }
}

Frontend Scripts

client/package.json
{
  "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:
server/src/index.ts
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

  • 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)

Build docs developers (and LLMs) love