Skip to content

API Docs (new)

Faisal Alkhrayef edited this page May 4, 2025 · 4 revisions

Student Club Management System API Documentation

Table of Contents

Authentication

OAuth2 Authentication

Google Authentication

GET /auth/google

Initiates Google OAuth2 authentication flow.

Response:

  • Redirects to Google consent screen

Google Callback

GET /google/callback

Handles Google OAuth2 callback.

Response:

  • Redirects to /update-profile for new users
  • Redirects to /profile for existing users

GitHub Authentication

GET /auth/github

Initiates GitHub OAuth2 authentication flow.

Response:

  • Redirects to GitHub consent screen

GitHub Callback

GET /github/callback

Handles GitHub OAuth2 callback.

Response:

  • Redirects to /update-profile for new users
  • Redirects to /profile for existing users

Session Management

Logout

GET /logout

Destroys the user's session.

Response:

  • Redirects to home page

Clubs

Club Management

Get All Clubs

GET /clubs

Query Parameters:

  • page (optional): Page number (default: 1)
  • limit (optional): Items per page (default: 10, max: 50)
  • sort (optional): Sort fields (e.g., -createdAt,name)
  • fields (optional): Fields to include (e.g., name,description,logo)
  • include (optional): Relations to include (e.g., supervisor,members)
  • search (optional): Search term
  • status[eq] (optional): Filter by status
  • type[eq] (optional): Filter by type

Response:

{
    "data": {
        "clubs": [
            {
                "id": 1,
                "name": "Programming Club",
                "description": "A club for programming enthusiasts",
                "logo": "https://example.com/logo.png",
                "type": "specialized",
                "status": "active",
                "foundingDate": "2024-01-01",
                "createdAt": "2024-01-01T00:00:00Z",
                "updatedAt": "2024-01-01T00:00:00Z"
            }
        ],
        "pagination": {
            "page": 1,
            "limit": 10,
            "total": 1,
            "pages": 1
        }
    }
}

Get Club by ID

GET /clubs/:clubId

Path Parameters:

  • clubId: Club ID

Query Parameters:

  • fields (optional): Fields to include
  • include (optional): Relations to include

Response:

{
    "data": {
        "id": 1,
        "name": "Programming Club",
        "description": "A club for programming enthusiasts",
        "logo": "https://example.com/logo.png",
        "type": "specialized",
        "status": "active",
        "foundingDate": "2024-01-01",
        "supervisor": {
            "id": 1,
            "name": "Dr. John Doe"
        },
        "members": [
            {
                "id": 1,
                "displayName": "Jane Smith",
                "role": "member"
            }
        ],
        "createdAt": "2024-01-01T00:00:00Z",
        "updatedAt": "2024-01-01T00:00:00Z"
    }
}

Create Club

POST /clubs

Request Body:

{
    "name": "Programming Club",
    "description": "A club for programming enthusiasts",
    "logo": "https://example.com/logo.png",
    "supervisorId": 1,
    "type": "specialized",
    "foundingDate": "2024-01-01"
}

Validation Rules:

  • name: String, min length 3, max length 100, unique
  • description: String, max length 500
  • logo: URL string, max length 4096
  • supervisorId: Positive integer
  • type: Enum ["general", "specialized"]
  • foundingDate: Optional date

Response:

{
    "data": {
        "id": 1,
        "name": "Programming Club",
        "description": "A club for programming enthusiasts",
        "logo": "https://example.com/logo.png",
        "type": "specialized",
        "status": "active",
        "foundingDate": "2024-01-01",
        "createdAt": "2024-01-01T00:00:00Z",
        "updatedAt": "2024-01-01T00:00:00Z"
    }
}

Update Club

PUT /clubs/:clubId

Path Parameters:

  • clubId: Club ID

Request Body:

{
    "name": "Updated Club Name",
    "description": "Updated description",
    "logo": "https://example.com/new-logo.png",
    "type": "general",
    "status": "inactive"
}

Validation Rules:

  • Same as create club, but all fields are optional

Response:

{
    "data": {
        "id": 1,
        "name": "Updated Club Name",
        "description": "Updated description",
        "logo": "https://example.com/new-logo.png",
        "type": "general",
        "status": "inactive",
        "updatedAt": "2024-01-02T00:00:00Z"
    }
}

Delete Club

DELETE /clubs/:clubId

Path Parameters:

  • clubId: Club ID

Response:

{
    "data": {
        "id": 1,
        "name": "Programming Club",
        "isArchived": true,
        "archivedAt": "2024-01-02T00:00:00Z",
        "updatedAt": "2024-01-02T00:00:00Z"
    }
}

Note: This endpoint performs a soft delete by setting isArchived to true. Archived records are automatically deleted after 1 year by a system cleanup job.

Membership Management

Get All Memberships

GET /clubs/:clubId/memberships

Path Parameters:

  • clubId: Club ID

Query Parameters:

  • page (optional): Page number (default: 1)
  • limit (optional): Items per page (default: 10, max: 50)
  • sort (optional): Sort fields (e.g., -joinedAt,role)
  • fields (optional): Fields to include
  • include (optional): Relations to include
  • status[eq] (optional): Filter by status
  • role[eq] (optional): Filter by role
  • isArchived[eq] (optional): Filter by archive status

Response:

{
    "data": {
        "memberships": [
            {
                "id": 1,
                "userId": 1,
                "clubId": 1,
                "role": "member",
                "status": "active",
                "tag": "2023-2",
                "joinedAt": "2024-01-01T00:00:00Z",
                "user": {
                    "id": 1,
                    "displayName": "Jane Smith",
                    "profileImage": "https://example.com/profile.jpg"
                }
            }
        ],
        "pagination": {
            "page": 1,
            "limit": 10,
            "total": 1,
            "pages": 1
        }
    }
}

Get Membership by ID

GET /clubs/:clubId/memberships/:membershipId

Path Parameters:

  • clubId: Club ID
  • membershipId: Membership ID

Query Parameters:

  • fields (optional): Fields to include
  • include (optional): Relations to include

Response:

{
    "data": {
        "id": 1,
        "userId": 1,
        "clubId": 1,
        "role": "member",
        "status": "active",
        "tag": "2023-2",
        "joinedAt": "2024-01-01T00:00:00Z",
        "user": {
            "id": 1,
            "displayName": "Jane Smith",
            "profileImage": "https://example.com/profile.jpg"
        }
    }
}

Create Membership

POST /clubs/:clubId/memberships

Path Parameters:

  • clubId: Club ID

Request Body:

{
    "userId": 1,
    "role": "member",
    "tag": "مدير المصممين"
}

Validation Rules:

  • userId: Positive integer
  • role: Enum ["clubAdmin", "hr", "member"]
  • tag: String, max length 50 (optional)

Response:

{
    "data": {
        "id": 1,
        "userId": 1,
        "clubId": 1,
        "role": "member",
        "status": "pending",
        "tag": "مدير كبير",
        "joinedAt": "2024-01-01T00:00:00Z"
    }
}

Note: This endpoint requires club admin privileges and creates a membership with "pending" status by default.

Join Club

POST /clubs/:clubId/memberships/me

Path Parameters:

  • clubId: Club ID

Response:

{
    "data": {
        "id": 1,
        "userId": 1,
        "clubId": 1,
        "role": "member",
        "status": "pending",
        "joinedAt": "2024-01-01T00:00:00Z"
    }
}

Note: This creates a membership application that must be reviewed by club administrators.

Update Membership

PUT /clubs/:clubId/memberships/:membershipId

Path Parameters:

  • clubId: Club ID
  • membershipId: Membership ID

Request Body:

{
    "role": "hr",
    "status": "active",
    "tag": "مدير المهمات الصعبة"
}

Validation Rules:

  • role: Enum ["clubAdmin", "hr", "member"]
  • status: Enum ["active", "inactive", "pending", "denied"]
  • tag: String, max length 50 (optional)

Response:

{
    "data": {
        "id": 1,
        "userId": 1,
        "clubId": 1,
        "role": "hr",
        "status": "active",
        "tag": "مدير المهمات الصعبة",
        "updatedAt": "2024-01-02T00:00:00Z"
    }
}

Note: Club administrators use this endpoint to accept or deny membership applications by updating the status.

Leave Club

DELETE /clubs/:clubId/memberships/me

Path Parameters:

  • clubId: Club ID

Response:

{
    "data": {
        "id": 1,
        "userId": 1,
        "clubId": 1,
        "role": "member",
        "status": "inactive",
        "updatedAt": "2024-01-02T00:00:00Z"
    }
}

Delete Membership

DELETE /clubs/:clubId/memberships/:membershipId

Path Parameters:

  • clubId: Club ID
  • membershipId: Membership ID

Response:

{
    "data": {
        "id": 1,
        "userId": 1,
        "clubId": 1,
        "isArchived": true,
        "archivedAt": "2024-01-02T00:00:00Z"
    }
}

Note: This endpoint performs a soft delete by setting isArchived to true. Archived memberships are automatically deleted after 1 year by a system cleanup job.

Archive Inactive Memberships

PUT /clubs/:clubId/memberships/inactive

Path Parameters:

  • clubId: Club ID

Response:

{
    "data": {
        "archivedCount": 15,
        "archivedMemberships": [
            {
                "id": 1,
                "userId": 1,
                "clubId": 1,
                "role": "member",
                "status": "inactive",
                "isArchived": true,
                "archivedAt": "2024-01-02T00:00:00Z",
                "volunteerHours": 45
            }
        ]
    }
}

Note: Archived memberships are automatically deleted after 1 year by a system cleanup job.

Events

Get All Events

GET /events

Query Parameters:

  • page (optional): Page number (default: 1)
  • limit (optional): Items per page (default: 10, max: 50)
  • sort (optional): Sort fields (e.g., -eventStart,name)
  • fields (optional): Fields to include
  • include (optional): Relations to include
  • search (optional): Search term
  • category[eq] (optional): Filter by category
  • clubId[eq] (optional): Filter by club ID
  • eventStart[gte] (optional): Filter by start date
  • eventEnd[lte] (optional): Filter by end date

Response:

{
    "data": {
        "events": [
            {
                "id": 1,
                "name": "Web Development Workshop",
                "description": "Learn web development basics",
                "poster": "https://example.com/poster.png",
                "location": "Room 101",
                "registrationStart": "2024-01-01T00:00:00Z",
                "registrationEnd": "2024-01-15T00:00:00Z",
                "eventStart": "2024-01-20T00:00:00Z",
                "eventEnd": "2024-01-21T00:00:00Z",
                "seatsAvailable": 50,
                "category": "workshop",
                "clubId": 1
            }
        ],
        "pagination": {
            "page": 1,
            "limit": 10,
            "total": 1,
            "pages": 1
        }
    }
}

Get Event by ID

GET /events/:eventId

Path Parameters:

  • eventId: Event ID

Query Parameters:

  • fields (optional): Fields to include
  • include (optional): Relations to include

Response:

{
    "data": {
        "id": 1,
        "name": "Web Development Workshop",
        "description": "Learn web development basics",
        "poster": "https://example.com/poster.png",
        "location": "Room 101",
        "registrationStart": "2024-01-01T00:00:00Z",
        "registrationEnd": "2024-01-15T00:00:00Z",
        "eventStart": "2024-01-20T00:00:00Z",
        "eventEnd": "2024-01-21T00:00:00Z",
        "seatsAvailable": 50,
        "category": "workshop",
        "club": {
            "id": 1,
            "name": "Programming Club"
        },
        "registrations": [
            {
                "id": 1,
                "user": {
                    "id": 1,
                    "displayName": "Jane Smith"
                },
                "status": "accepted"
            }
        ]
    }
}

Create Event

POST /clubs/:clubId/events

Path Parameters:

  • clubId: Club ID

Request Body:

{
    "name": "Web Development Workshop",
    "description": "Learn web development basics",
    "poster": "https://example.com/poster.png",
    "location": "Room 101",
    "registrationStart": "2024-01-01T00:00:00Z",
    "registrationEnd": "2024-01-15T00:00:00Z",
    "eventStart": "2024-01-20T00:00:00Z",
    "eventEnd": "2024-01-21T00:00:00Z",
    "seatsAvailable": 50,
    "category": "workshop"
}

Validation Rules:

  • name: String, min length 3, max length 100
  • description: String, max length 1000
  • poster: URL string, max length 4096
  • location: String, min length 3, max length 255
  • registrationStart: Date
  • registrationEnd: Date (must be after registrationStart)
  • eventStart: Date (must be after registrationEnd)
  • eventEnd: Date (must be after eventStart)
  • seatsAvailable: Integer, min 1, max 10000
  • category: Enum ["bootcamp", "workshop", "meeting", "hackathon", "seminar", "conference", "networking"]

Response:

{
    "data": {
        "id": 1,
        "name": "Web Development Workshop",
        "description": "Learn web development basics",
        "poster": "https://example.com/poster.png",
        "location": "Room 101",
        "registrationStart": "2024-01-01T00:00:00Z",
        "registrationEnd": "2024-01-15T00:00:00Z",
        "eventStart": "2024-01-20T00:00:00Z",
        "eventEnd": "2024-01-21T00:00:00Z",
        "seatsAvailable": 50,
        "category": "workshop",
        "clubId": 1,
        "createdAt": "2024-01-01T00:00:00Z",
        "updatedAt": "2024-01-01T00:00:00Z"
    }
}

Update Event

PUT /events/:eventId

Path Parameters:

  • eventId: Event ID

Request Body:

{
    "name": "Updated Workshop Name",
    "description": "Updated description",
    "poster": "https://example.com/new-poster.png",
    "location": "Room 102",
    "seatsAvailable": 60
}

Validation Rules:

  • Same as create event, but all fields are optional

Response:

{
    "data": {
        "id": 1,
        "name": "Updated Workshop Name",
        "description": "Updated description",
        "poster": "https://example.com/new-poster.png",
        "location": "Room 102",
        "seatsAvailable": 60,
        "updatedAt": "2024-01-02T00:00:00Z"
    }
}

Apply for Event

POST /events/:eventId/registrations

Path Parameters:

  • eventId: Event ID

Response:

{
    "data": {
        "id": 1,
        "userId": 1,
        "eventId": 1,
        "status": "pending",
        "createdAt": "2024-01-01T00:00:00Z"
    }
}

Get User Event Registrations

GET /events/registrations/me

Query Parameters:

  • page (optional): Page number (default: 1)
  • limit (optional): Items per page (default: 10, max: 50)
  • status[eq] (optional): Filter by status
  • include (optional): Relations to include

Response:

{
    "data": {
        "registrations": [
            {
                "id": 1,
                "eventId": 1,
                "status": "pending",
                "createdAt": "2024-01-01T00:00:00Z",
                "event": {
                    "id": 1,
                    "name": "Web Development Workshop",
                    "eventStart": "2024-01-20T00:00:00Z"
                }
            }
        ],
        "pagination": {
            "page": 1,
            "limit": 10,
            "total": 1,
            "pages": 1
        }
    }
}

Get Event Registrations

GET /events/:eventId/registrations

Path Parameters:

  • eventId: Event ID

Query Parameters:

  • page (optional): Page number (default: 1)
  • limit (optional): Items per page (default: 10, max: 50)
  • status[eq] (optional): Filter by status
  • include (optional): Relations to include

Response:

{
    "data": {
        "registrations": [
            {
                "id": 1,
                "userId": 1,
                "status": "pending",
                "createdAt": "2024-01-01T00:00:00Z",
                "user": {
                    "id": 1,
                    "displayName": "Jane Smith",
                    "profileImage": "https://example.com/profile.jpg"
                }
            }
        ],
        "pagination": {
            "page": 1,
            "limit": 10,
            "total": 1,
            "pages": 1
        }
    }
}

Update Registration Status

PUT /events/:eventId/registrations/:registrationId

Path Parameters:

  • eventId: Event ID
  • registrationId: Registration ID

Request Body:

{
    "status": "accepted"
}

Validation Rules:

  • status: Enum ["pending", "accepted", "rejected"]

Response:

{
    "data": {
        "id": 1,
        "userId": 1,
        "eventId": 1,
        "status": "accepted",
        "updatedAt": "2024-01-02T00:00:00Z"
    }
}

Cancel Registration

DELETE /events/:eventId/registrations/me

Path Parameters:

  • eventId: Event ID

Response:

{
    "data": {
        "message": "Successfully canceled event registration"
    }
}

Tasks

Task Management

Get All Tasks

GET /tasks

Query Parameters:

  • page (optional): Page number (default: 1)
  • limit (optional): Items per page (default: 10, max: 50)
  • sort (optional): Sort fields (e.g., -createdAt,title)
  • fields (optional): Fields to include
  • include (optional): Relations to include
  • search (optional): Search term
  • status[eq] (optional): Filter by status
  • category[eq] (optional): Filter by category
  • clubMembershipId[eq] (optional): Filter by club membership ID

Response:

{
    "data": {
        "tasks": [
            {
                "id": 1,
                "title": "Website Development",
                "description": "Develop club website",
                "volunteeredSeconds": 7200,
                "category": "club_programs_projects",
                "status": "pending",
                "attachment": "https://example.com/attachment.pdf",
                "reviewComment": null,
                "clubMembership": {
                    "id": 1,
                    "user": {
                        "id": 1,
                        "displayName": "Jane Smith"
                    }
                },
                "createdAt": "2024-01-01T00:00:00Z",
                "updatedAt": "2024-01-01T00:00:00Z"
            }
        ],
        "pagination": {
            "page": 1,
            "limit": 10,
            "total": 1,
            "pages": 1
        }
    }
}

Get Task by ID

GET /tasks/:taskId

Path Parameters:

  • taskId: Task ID

Query Parameters:

  • fields (optional): Fields to include
  • include (optional): Relations to include

Response:

{
    "data": {
        "id": 1,
        "title": "Website Development",
        "description": "Develop club website",
        "volunteeredSeconds": 7200,
        "category": "club_programs_projects",
        "status": "pending",
        "attachment": "https://example.com/attachment.pdf",
        "reviewComment": null,
        "clubMembership": {
            "id": 1,
            "user": {
                "id": 1,
                "displayName": "Jane Smith"
            }
        },
        "createdByUser": {
            "id": 1,
            "displayName": "John Doe"
        },
        "updatedByUser": {
            "id": 1,
            "displayName": "John Doe"
        },
        "createdAt": "2024-01-01T00:00:00Z",
        "updatedAt": "2024-01-01T00:00:00Z"
    }
}

Create Task

POST /tasks

Request Body:

{
    "clubMembershipId": 1,
    "title": "Website Development",
    "description": "Develop club website",
    "volunteeredSeconds": 7200,
    "category": "club_programs_projects",
    "attachment": "https://example.com/attachment.pdf"
}

Validation Rules:

  • clubMembershipId: Positive integer
  • title: String, min length 1, max length 100
  • description: String, min length 1, max length 500
  • volunteeredSeconds: Integer, min 0
  • category: Enum ["club_programs_projects", "uni_collab", "external_collab", "club_initiatives", "internal_activities", "community_contributions"]
  • attachment: URL string, max length 4096 (optional)

Response:

{
    "data": {
        "id": 1,
        "title": "Website Development",
        "description": "Develop club website",
        "volunteeredSeconds": 7200,
        "category": "club_programs_projects",
        "status": "pending",
        "attachment": "https://example.com/attachment.pdf",
        "reviewComment": null,
        "createdAt": "2024-01-01T00:00:00Z",
        "updatedAt": "2024-01-01T00:00:00Z"
    }
}

Update Task

PUT /tasks/:taskId

Path Parameters:

  • taskId: Task ID

Request Body:

{
    "title": "Updated Website Development",
    "description": "Updated description",
    "volunteeredSeconds": 9000,
    "category": "club_initiatives",
    "attachment": "https://example.com/new-attachment.pdf",
    "status": "accepted",
    "reviewComment": "Great work! Approved."
}

Validation Rules:

  • Same as create task, but all fields are optional
  • status: Enum ["accepted", "changes_requested", "denied", "pending"]
  • reviewComment: String, max length 500 (optional)

Response:

{
    "data": {
        "id": 1,
        "title": "Updated Website Development",
        "description": "Updated description",
        "volunteeredSeconds": 9000,
        "category": "club_initiatives",
        "status": "accepted",
        "attachment": "https://example.com/new-attachment.pdf",
        "reviewComment": "Great work! Approved.",
        "updatedAt": "2024-01-02T00:00:00Z"
    }
}

Delete Task

DELETE /tasks/:taskId

Path Parameters:

  • taskId: Task ID

Response:

{
    "data": {
        "id": 1,
        "isArchived": true,
        "archivedAt": "2024-01-02T00:00:00Z"
    }
}

Note: This endpoint performs a soft delete by setting isArchived to true. Archived tasks are automatically deleted after 1 year by a system cleanup job.

Profile

Update Profile

PUT /profile

Request Body:

{
    "displayName": "John Doe",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com",
    "uniId": "123456789",
    "nationalId": "1234567890",
    "phoneNumber": "1234567890",
    "profileImage": "https://example.com/profile.jpg"
}

Validation Rules:

  • displayName: String, min length 2
  • firstName: String, min length 2
  • lastName: String (optional)
  • email: Valid email address, unique
  • uniId: String, length 9 (optional)
  • nationalId: String, length 10, digits only
  • phoneNumber: String, length 10, digits only
  • profileImage: URL string

Response:

{
    "data": {
        "id": 1,
        "displayName": "John Doe",
        "firstName": "John",
        "lastName": "Doe",
        "email": "john@example.com",
        "uniId": "123456789",
        "nationalId": "1234567890",
        "phoneNumber": "1234567890",
        "profileImage": "https://example.com/profile.jpg",
        "updatedAt": "2024-01-02T00:00:00Z"
    }
}

Delete Account

DELETE /profile

Response:

{
    "data": {
        "message": "Account successfully deleted"
    }
}

Query Parameters

Pagination

  • page: Page number (default: 1)
  • limit: Items per page (default: 10, max: 50)

Sorting

  • sort: Comma-separated fields with optional - prefix for descending order
    • Example: -createdAt,name

Field Selection

  • fields: Comma-separated list of fields to include
    • Example: name,description,logo

Relation Inclusion

  • include: Comma-separated list of relations to include
    • Example: supervisor,members

Filtering

  • field[operator]=value format
  • Operators:
    • eq: Equal to
    • neq: Not equal to
    • gt: Greater than
    • gte: Greater than or equal to
    • lt: Less than
    • lte: Less than or equal to
    • in: In array (comma-separated values)
    • nin: Not in array (comma-separated values)
    • like: Pattern matching
    • ilike: Case-insensitive pattern matching

Search

  • search: Search term for text fields

Error Codes

HTTP Status Codes

The API uses standard HTTP status codes to indicate the success or failure of requests:

  • 200 OK: Request succeeded
  • 201 Created: Resource created successfully
  • 204 No Content: Request succeeded but no content returned
  • 400 Bad Request: Invalid request parameters
  • 401 Unauthorized: Authentication required
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Resource not found
  • 409 Conflict: Resource conflict (e.g., already exists)
  • 500 Internal Server Error: Server error

Error Response Format

All error responses follow this format:

{
    "error": {
        "code": "ERROR_CODE",
        "message": "Human readable error message",
        "details": {
            // Optional additional error details
        }
    }
}

Common Error Codes

  • INVALID_REQUEST: Invalid request parameters or malformed request
  • UNAUTHORIZED: Authentication required or invalid credentials
  • FORBIDDEN: User lacks required permissions
  • NOT_FOUND: Requested resource not found
  • CONFLICT: Resource conflict (e.g., already exists)
  • VALIDATION_ERROR: Input validation failed
  • INTERNAL_ERROR: Internal server error

System Cleanup

The system includes an automated cleanup job that permanently deletes archived records after they have been archived for 1 year. This applies to:

  • Archived clubs
  • Archived memberships
  • Archived events

The cleanup job runs daily and only affects records that have been archived for more than 365 days.

Clone this wiki locally