Skip to main content

Welcome to MarsAI

This guide will help you get from installation to your first meaningful action on the MarsAI film festival platform. You’ll learn how to create accounts, submit films, vote as a jury member, and manage users as an administrator.
Make sure you’ve completed the Installation guide before proceeding. You should have both backend and frontend servers running.

Overview

The MarsAI platform supports three user roles:
  • PRODUCER - Submit films to the festival
  • JURY - Review and vote on assigned films
  • ADMIN - Manage users, films, categories, and awards

Create Your First Admin Account

1

Navigate to registration page

Open your browser and go to http://localhost:5173/auth/register
2

Fill in admin details

Register a new account with the ADMIN role:
{
  "first_name": "Admin",
  "last_name": "User",
  "email": "admin@marsai.com",
  "password": "SecurePass123!",
  "role": "ADMIN"
}
Or use the API directly:
curl -X POST http://localhost:3000/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Admin",
    "last_name": "User",
    "email": "admin@marsai.com",
    "password": "SecurePass123!",
    "role": "ADMIN"
  }'
3

Login to get your token

curl -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@marsai.com",
    "password": "SecurePass123!"
  }'
Response:
{
  "message": "Connexion réussie",
  "data": {
    "email": "admin@marsai.com",
    "first_name": "Admin",
    "role": "ADMIN",
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}
Save the token - you’ll need it for authenticated requests. The token is valid for 1 hour by default.
4

Access admin dashboard

Login via the UI at http://localhost:5173/auth/login with your admin credentials.You’ll be redirected to http://localhost:5173/admin where you can:
  • View dashboard statistics
  • Manage users
  • Review film submissions
  • Configure categories and awards
  • Assign films to jury members

Producer Workflow: Submit Your First Film

Let’s walk through submitting a film as a producer.
1

Create a producer account

Register a producer account:
src/api/auth.js
const response = await signIn({
  first_name: "Jane",
  last_name: "Director",
  email: "jane@filmmaker.com",
  password: "FilmPass123!",
  role: "PRODUCER"
});
Or use the registration form at http://localhost:5173/auth/register
2

Login as producer

Login and navigate to the producer dashboard at http://localhost:5173/producer
3

Submit a film

Use the film submission form or API:
# Login first to get your token
TOKEN="your-jwt-token-here"

# Submit film with metadata and files
curl -X POST http://localhost:3000/movies/upload \
  -H "Authorization: Bearer $TOKEN" \
  -F "title=Mars Chronicles" \
  -F "synopsis=A documentary about human life on Mars" \
  -F "duration=95" \
  -F "release_year=2026" \
  -F "language=English" \
  -F "filmFile=@/path/to/film.mp4" \
  -F "thumbnail1=@/path/to/poster1.jpg" \
  -F "thumbnail2=@/path/to/poster2.jpg" \
  -F "subtitlesSrt=@/path/to/subtitles.srt"
The frontend implementation:
src/api/movies.js
import { createMovie } from './api/movies';

async function submitFilm() {
  const formData = new FormData();
  formData.append('title', 'Mars Chronicles');
  formData.append('synopsis', 'A documentary about human life on Mars');
  formData.append('duration', '95');
  formData.append('release_year', '2026');
  formData.append('language', 'English');
  formData.append('filmFile', filmFileInput.files[0]);
  formData.append('thumbnail1', poster1Input.files[0]);
  
  const response = await createMovie(formData);
  console.log('Film submitted:', response.data);
}
Film files should be in MP4 format. Maximum file size depends on your server configuration. Thumbnails should be JPG or PNG images.
4

View your submitted films

Retrieve your films:
src/api/movies.js
import { getMyMovies } from './api/movies';

const response = await getMyMovies();
const myFilms = response.data;
Or via API:
curl -X GET http://localhost:3000/movies/mine \
  -H "Authorization: Bearer $TOKEN"
Each film will have a status:
  • PENDING - Awaiting admin review
  • VALIDATED - Approved and assigned to jury
  • CANDIDATE - Shortlisted by jury
  • REJECTED - Not accepted to festival

Jury Workflow: Vote on Films

Jury members review assigned films and vote on them.
1

Create a jury account

An admin must create jury accounts:
curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -d '{
    "first_name": "Sarah",
    "last_name": "Critic",
    "email": "sarah@jury.com",
    "password": "JuryPass123!",
    "role": "JURY"
  }'
2

Admin assigns films to jury

The admin assigns specific films to jury members:
curl -X PUT http://localhost:3000/movies/1/juries \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -d '{
    "juries": [2, 3, 4]
  }'
This assigns film with id_movie=1 to jury members with IDs 2, 3, and 4.
3

Jury views assigned films

Login as jury member at http://localhost:5173/auth/login and navigate to /jury.Fetch assigned films via API:
// GET /movies/assigned
const response = await instance.get('movies/assigned');
const assignedFilms = response.data;
Or with curl:
curl -X GET http://localhost:3000/movies/assigned \
  -H "Authorization: Bearer $JURY_TOKEN"
4

Submit a vote

Jury members can vote on assigned films:
src/api/votes.js
import { submitMyVote } from './api/votes';

// Vote on film with id_movie = 5
const response = await submitMyVote(5, {
  score: 8.5,
  comment: "Exceptional cinematography and storytelling",
  is_candidate: true
});
Or via API:
curl -X POST http://localhost:3000/votes/mine/5 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $JURY_TOKEN" \
  -d '{
    "score": 8.5,
    "comment": "Exceptional cinematography",
    "is_candidate": true
  }'
Setting is_candidate: true promotes the film to candidate status. Each jury member can vote only once per film, but can update their vote.
5

View your votes

Retrieve all your votes:
src/api/votes.js
import { getMyVotes } from './api/votes';

const response = await getMyVotes();
const myVotes = response.data;
Or get your vote for a specific film:
import { getMyVoteByMovie } from './api/votes';

const response = await getMyVoteByMovie(5);
const vote = response.data;

Admin Workflow: Manage Users and Films

Administrators have full control over the platform.

Managing Users

1

View all users

curl -X GET http://localhost:3000/users \
  -H "Authorization: Bearer $ADMIN_TOKEN"
Frontend implementation:
src/api/users.js
import instance from './config';

async function getUsers() {
  return await instance.get('users');
}

const response = await getUsers();
const allUsers = response.data;
2

Create a new user

Create users with any role:
const newUser = {
  first_name: "John",
  last_name: "Jury",
  email: "john@jury.com",
  password: "SecurePass123!",
  role: "JURY"  // or "PRODUCER", "ADMIN"
};

const response = await instance.post('users', newUser);
3

Update user details

curl -X PUT http://localhost:3000/users/5 \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -d '{
    "first_name": "Jane",
    "role": "ADMIN"
  }'
4

Delete a user

curl -X DELETE http://localhost:3000/users/5 \
  -H "Authorization: Bearer $ADMIN_TOKEN"
Deleting a user is permanent. Associated data (films, votes) may also be affected.

Managing Films

1

View all films

Public endpoint (no authentication required):
curl -X GET http://localhost:3000/movies
Or get a specific film:
curl -X GET http://localhost:3000/movies/1
2

Update film status

Change film status from PENDING to VALIDATED:
curl -X PUT http://localhost:3000/movies/1/status \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -d '{
    "status": "VALIDATED"
  }'
Available statuses:
  • PENDING - Initial submission
  • VALIDATED - Approved by admin
  • CANDIDATE - Shortlisted by jury
  • REJECTED - Not accepted
3

Assign categories to film

curl -X PUT http://localhost:3000/movies/1/categories \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -d '{
    "categories": [1, 3, 5]
  }'
This assigns category IDs 1, 3, and 5 to the film.
4

Assign jury members to film

curl -X PUT http://localhost:3000/movies/1/juries \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -d '{
    "juries": [2, 4, 7]
  }'
Jury members with IDs 2, 4, and 7 will now see this film in their assigned films list.
5

Delete a film

curl -X DELETE http://localhost:3000/movies/1 \
  -H "Authorization: Bearer $ADMIN_TOKEN"

Understanding Authentication

All authenticated requests require a JWT token in the Authorization header.

Getting a Token

src/api/auth.js
import { login } from './api/auth';

const response = await login({
  email: "user@example.com",
  password: "password123"
});

const { token, role, first_name } = response.data;

// Store token in localStorage
localStorage.setItem('token', token);
localStorage.setItem('role', role);
localStorage.setItem('firstName', first_name);

Using the Token

The Axios instance automatically adds the token to requests:
src/api/config.js
// Interceptor adds token to all requests
instance.interceptors.request.use(
  async (config) => {
    const token = localStorage.getItem("token");
    
    if (token !== null) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    
    return config;
  }
);

Token Expiration

Tokens expire after 1 hour by default. When a token expires:
// The response interceptor handles 401 errors
instance.interceptors.response.use(
  (response) => response,
  async (error) => {
    if (error.response && error.response.status === 401) {
      // Clear stored auth data
      localStorage.removeItem("token");
      localStorage.removeItem("role");
      // Redirect to login
      window.location.href = "/auth/login";
    }
    return Promise.reject(error);
  }
);

API Endpoints Reference

Authentication Routes

MethodEndpointDescriptionAuth Required
POST/auth/registerCreate new accountNo
POST/auth/loginLogin and get tokenNo
POST/auth/register-filmRegister producer + submit filmNo

User Routes

MethodEndpointDescriptionAuth Required
GET/users/meGet current user profileYes (All roles)
PUT/users/meUpdate current userYes (All roles)
GET/usersGet all usersYes (ADMIN)
GET/users/:idGet user by IDYes (ADMIN)
POST/usersCreate new userNo*
PUT/users/:idUpdate userYes (ADMIN)
DELETE/users/:idDelete userYes (ADMIN)
*Typically called by admins, but endpoint is open for registration flow.

Movie Routes

MethodEndpointDescriptionAuth Required
GET/moviesGet all films (public)No
GET/movies/:idGet film by IDNo
GET/movies/mineGet my filmsYes (PRODUCER)
POST/movies/uploadSubmit new filmYes (PRODUCER)
GET/movies/assignedGet assigned filmsYes (JURY)
PUT/movies/:idUpdate filmYes (ADMIN)
PUT/movies/:id/statusUpdate film statusYes (ADMIN)
PUT/movies/:id/categoriesAssign categoriesYes (ADMIN)
PUT/movies/:id/juriesAssign jury membersYes (ADMIN)
PUT/movies/:id/collaboratorsUpdate collaboratorsYes (PRODUCER, ADMIN)
DELETE/movies/:idDelete filmYes (ADMIN)

Vote Routes

MethodEndpointDescriptionAuth Required
GET/votes/mineGet my votesYes (JURY, ADMIN)
GET/votes/mine/:id_movieGet my vote for filmYes (JURY, ADMIN)
POST/votes/mine/:id_movieCreate/update my voteYes (JURY, ADMIN)
GET/votesGet all votesYes (ADMIN)
DELETE/votes/movie/:id_movieDelete all votes for filmYes (ADMIN)
DELETE/votes/:idDelete vote by IDYes (ADMIN)

Next Steps

Now that you understand the basics:

API Reference

Explore detailed API documentation

User Guides

Learn advanced user management

Film Submission

Learn about film submission and categories

Voting System

Understand the jury voting workflow

Common Use Cases

Use the combined registration endpoint:
curl -X POST http://localhost:3000/auth/register-film \
  -F "first_name=Maria" \
  -F "last_name=Producer" \
  -F "email=maria@films.com" \
  -F "password=SecurePass123!" \
  -F "title=My First Film" \
  -F "synopsis=An amazing story" \
  -F "duration=120" \
  -F "filmFile=@film.mp4" \
  -F "thumbnail1=@poster.jpg"
This creates both the user account and the film submission in a single transaction.
curl -X PUT http://localhost:3000/movies/5/jury-candidate \
  -H "Authorization: Bearer $JURY_TOKEN"
This marks the film as a candidate without submitting a full vote.
import instance from './api/config';

const response = await instance.get('users/me');
const currentUser = response.data;

console.log(`Welcome ${currentUser.first_name}!`);
console.log(`Role: ${currentUser.role}`);

Troubleshooting

Your token may have expired or is invalid:
  1. Login again to get a fresh token
  2. Check that the token is being sent in the Authorization header
  3. Verify the token format: Bearer <token>
Common issues:
  • File too large (check server limits)
  • Wrong file type (must be MP4 for films)
  • Content-Type header must be multipart/form-data
  • Ensure uploads/ directory exists and is writable
Check your role:
const role = localStorage.getItem('role');
console.log('Current role:', role);
Routes are protected by role:
  • /admin/* requires ADMIN role
  • /jury/* requires JURY role
  • /producer/* requires PRODUCER role