Skip to main content
The user management system handles user accounts, authentication, roles, and student progress tracking.

User Data Model

The platform uses MongoDB with Prisma for user data storage.

User Schema

id
string
MongoDB ObjectId - unique user identifier
email
string
required
User’s email address (unique, used for authentication)
name
string
required
User’s full name
image
string
Profile image URL from OAuth provider
localidad
string
default:"-"
User’s location/city
telefono
number
default:"0"
Phone number
nivel
enum
default:"inicial"
English level: inicial, basico, intermedio, or avanzado
status
boolean
default:"false"
Account status flag
newsletter
enum
default:"no"
Newsletter subscription: si or no
totalClasses
number
default:"0"
Total number of completed classes
googleRefreshToken
string
OAuth refresh token for Google services (admin only)
Schema Reference: prisma/schema.prisma:111-128

Role System

The platform supports three user roles:

Role Definitions

USER
role
Standard user with access to student features
ADMIN
role
Administrator with full platform access
MOD
role
Moderator with elevated permissions (reserved for future use)
Enum Definition: prisma/schema.prisma:16-20
Currently, admin status is determined by email match with ADMIN_EMAIL environment variable rather than a database role field.

User Authentication

Authentication is handled through NextAuth.js with OAuth providers.

Supported Providers

  1. GitHub OAuth
  2. Google OAuth (with Calendar API access)

Authentication Flow

1. Sign In Callback

Implementation: src/auth.ts:35-53
async signIn({ user, account, profile }) {
  const { name, email, image } = user as User
  
  const userFound = await loggedAsAdmin(email)
  
  if (!userFound) {
    await createUser(name, email, image)
    return true
  }
  
  return true
}
New users are automatically created on first sign-in.

2. JWT Token Handling

Implementation: src/auth.ts:55-85 Tokens include:
  • User ID
  • Access token for API calls
  • Refresh token (admin only)
  • 30-day expiration

3. Session Management

Implementation: src/auth.ts:87-104 Session data includes:
  • User profile information
  • JWT tokens
  • Access and refresh tokens
  • Token expiration times

Session Configuration

maxAge
number
default:"2592000"
Session duration: 30 days (60 * 60 * 24 * 30 seconds)
updateAge
number
default:"43200"
Session update interval: 12 hours

User Creation

New users are created automatically during OAuth sign-in: Server Action: src/server-actions/actions.ts:26-42
export async function createUser(name: string, email: string, image: string) {
  try {
    const newUser = await db.user.create({
      data: {
        name,
        email,
        image
      }
    })
    return true
  } catch (error) {
    console.error("We found an error creating this new user: ", error)
    return { message: "We found an error creating this new user", status: 500 }
  }
}
User creation uses default values from schema for optional fields (localidad, telefono, nivel, etc.).

User Profile Management

Users can update their profile information after account creation.

Retrieving User Data

Function: src/services/functions/index.ts:39-55
export async function getUserData({ id }: { id: string }) {
  try {
    const response = await db.user.findUnique({
      where: { id },
      select: {
        localidad: true,
        nivel: true,
        telefono: true,
        newsletter: true
      }
    })
    return response
  } catch (error) {
    console.log(error);
    return error
  }
}

Updating User Data

Function: src/services/functions/index.ts:58-74
export async function updateUserData({
  id,
  localidad,
  nivel,
  telefono,
  newsletter
}: {
  id: string,
  localidad: string,
  nivel: $Enums.NivelIngles,
  telefono: number,
  newsletter: 'si' | 'no'
}) {
  try {
    const response = await db.user.update({
      where: { id },
      data: { localidad, nivel, telefono, newsletter }
    })
    return response
  } catch (error) {
    console.log(error);
    return error
  }
}

English Level Management

Users can set their English proficiency level:

Level Options

LevelDescription
inicialBeginner/Initial level
basicoBasic level
intermedioIntermediate level
avanzadoAdvanced level
Enum Definition: prisma/schema.prisma:28-33 Level selection affects:
  • Activity difficulty recommendations
  • Class matching
  • Progress tracking

User Activity Tracking

Student progress is tracked through the UserActivity model:

UserActivity Schema

userId
string
required
Reference to User ID
taskId
string
Reference to assigned Task
classId
string
required
Reference to VirtualClass
rol
enum
required
User’s role in class: anfitrion (host) or participante (participant)
completed
boolean
default:"false"
Whether the activity has been completed
Schema Reference: prisma/schema.prisma:168-180

Creating Activity Records

When a user joins or creates a class:
await db.userActivity.create({
  data: {
    userId: newClass.bookedById,
    classId: newClass.id,
    taskId: null,
    rol: 'anfitrion',
    completed: false
  }
})
Implementation: src/services/functions/index.ts:229-237

Admin User Features

Administrators have additional capabilities:

Refresh Token Storage

Only admin users store Google OAuth refresh tokens:
if (profile.email === process.env.ADMIN_EMAIL! && account.refresh_token) {
  token.refreshToken = account.refresh_token
  await updateRefreshTokenInDb(user.id, token.refreshToken as string)
}
Implementation: src/auth.ts:73-76 This enables:
  • Persistent Google Calendar access
  • Creating events on behalf of the platform
  • Accessing Calendar API without repeated authorization

Refresh Token Database Storage

Function: src/services/functions/index.ts:9-22
export async function updateRefreshTokenInDb(userId: string, refreshToken: string) {
  try {
    const response = await db.user.update({
      where: { id: userId },
      data: {
        googleRefreshToken: refreshToken
      }
    })
    return response
  } catch (error) {
    console.log(error);
    return error
  }
}

Total Classes Counter

The totalClasses field tracks completed classes per user:

Incrementing Class Count

After activity upload for a class:
await db.user.updateMany({
  where: {
    id: { in: userIds }
  },
  data: {
    totalClasses: { increment: 1 }
  }
})
Implementation: src/app/(dashboard)/admin/actividad/[classId]/actions.ts:98-110 This counter:
  • Increments when admin uploads activity for a class
  • Tracks all participants in the class
  • Provides student progress metrics

User Relationships

Users are related to multiple entities:

One-to-Many Relationships

  • UserActivity[] - All user’s class activities
  • PaymentMercadoPago[] - User’s payment records
  • SupportTicket[] - User’s support tickets

Through Virtual Classes

  • Classes hosted (via bookedById)
  • Classes attended (via participantsIds array)

Security Considerations

User emails are unique and used as the primary authentication identifier. Never expose user IDs or email addresses in client-side code.

Admin Email Protection

Admin status should never be stored in client-accessible state:
// Server-side check only
const isAdmin = session?.user.email === process.env.ADMIN_EMAIL!

Session Security

  • Sessions expire after 30 days
  • JWT tokens are signed and validated
  • Refresh tokens are only stored for admin users
  • OAuth providers handle password management

Authentication Setup

Configure OAuth providers and authentication

Class Management

Understand how users interact with classes

Build docs developers (and LLMs) love