Know your AI API is a RESTful backend that collects user activity via the YouTube Data API and transforms it into an AI-generated profile using Hugging Face models.
The goal? 👉 Help users understand how their data is interpreted by AI systems.
-
🔐 Authentication & Authorization
-
JWT-based login system
-
Role-based access control (admin/user)
-
-
🧠 AI Profile Generation
-
Import YouTube data
-
Generate behavioral themes via Hugging Face
-
-
🎮 Interactive Learning
-
Create and manage quizzes (learning modules)
-
Multiplayer minigame system (matches & sessions)
-
-
👨👩👧 Family System
-
Group users into families
-
Shared learning experiences
-
-
📊 Data Transparency
-
Expose collected data (read-only endpoints)
-
Let users explore their own AI profiles
-
| Layer | Technology |
|---|---|
| Backend | Node.js + Express |
| Database | MySQL2 |
| AI Service | Python + Hugging Face |
| Auth | JWT |
| External API | YouTube Data API |
📦 Prerequisites
-
Node.js ≥ 18.x
-
npm or yarn
-
MySQL / phpMyAdmin
-
Git
📥 1. Clone the Repository
git clone https://github.com/Frutiger-Aero/TLE-3-backend.git
cd TLE-3-back-end📦 2. Install Dependencies
npm install📦 3. Set up the Database
- Create a MySQL database.
- Import the provided SQL schema into your MySQL server (e.g., via phpMyAdmin or MySQL CLI).
🔐 4. Environment Variables
Create a .env file in the root directory:
# Database
DB_HOST=
DB_USER=
DB_PASSWORD=
DB_NAME=
# Auth
JWT_SECRET=
JWT_EXPIRES_IN=
# YouTube OAuth
YOUTUBE_CLIENT_ID=
YOUTUBE_CLIENT_SECRET=
YOUTUBE_REDIRECT_URI=npm run deverDiagram
USERS {
bigint id PK
varchar username
varchar email UK
varchar password
bigint role
bigint family_id FK
datetime created_at
}
FAMILIES {
bigint id PK
bigint user_id FK
bigint family_admin FK
datetime created_at
}
AI_ATTITUDES {
int id PK
int life
int work
int future
int opinion
int score
int user_id
datetime created_at
datetime updated_at
}
AI_PROFILES {
bigint id PK
bigint user_id FK
text liked_video_titles
text liked_video_descriptions
text liked_video_tags
datetime created_at
}
THEMES {
bigint id PK
bigint profile_id FK
text movie
text movie_genre
text artist
text food
text place
text music
text music_genre
text holiday_country
text clothing_style
text animal
text color
timestamp created_at
}
QUIZZES {
bigint id PK
varchar name
bigint theme_id FK
bigint times_played
datetime created_at
text description
}
QUESTIONS {
bigint id PK
bigint quiz_id FK
text description
datetime created_at
}
ANSWERS {
bigint id PK
bigint question_id FK
boolean is_correct
datetime created_at
bigint user_id FK
}
FAMILY_QUIZZES {
bigint id PK
bigint family_id FK
bigint quiz_id FK
datetime created_at
}
LOGS {
bigint id PK
bigint user_id FK
varchar action
datetime timestamp
}
MINIGAMES {
bigint id PK
varchar name
text description
datetime created_at
bigint theme_id FK
varchar game_type
}
MINIGAME_MATCHES {
bigint id PK
bigint minigame_id FK
varchar status
varchar join_code
bigint created_by_user_id FK
datetime created_at
datetime ended_at
}
MATCH_USERS {
bigint id PK
bigint match_id FK
bigint user_id FK
bigint team
boolean is_host
datetime joined_at
datetime left_at
}
MINIGAME_SESSIONS {
bigint id PK
bigint minigame_id FK
bigint user_id FK
datetime start_time
datetime end_time
time duration
bigint score
json result
bigint match_id FK
}
MINIGAME_EVENTS {
bigint id PK
bigint session_id FK
enum event_type
json event_data
datetime timestamp
}
RECOMMENDATIONS {
bigint id PK
bigint user_id FK
bigint minigame_id FK
bigint quiz_id FK
text recommendation
text explanation
decimal confidence_score
boolean response
datetime created_at
}
USER_MINIGAMES {
bigint id PK
bigint user_id FK
bigint family_id FK
bigint minigame_id FK
datetime created_at
}
YOUTUBE_TOKENS {
bigint id PK
bigint user_id FK
text access_token
text refresh_token
varchar youtube_channel_id
varchar youtube_channel_name
datetime created_at
datetime updated_at
}
%% Explicit foreign-key relationships
USERS o|--|| FAMILIES : "family_id -> id"
FAMILIES ||--o{ USERS : "id <- family_id"
USERS ||--o{ AI_PROFILES : "id <- user_id"
AI_PROFILES o|--o{ THEMES : "id <- profile_id"
THEMES ||--o{ QUIZZES : "id <- theme_id"
THEMES ||--o{ MINIGAMES : "id <- theme_id"
QUIZZES ||--o{ QUESTIONS : "id <- quiz_id"
QUESTIONS ||--o{ ANSWERS : "id <- question_id"
USERS o|--o{ ANSWERS : "id <- user_id"
FAMILIES ||--o{ FAMILY_QUIZZES : "id <- family_id"
QUIZZES ||--o{ FAMILY_QUIZZES : "id <- quiz_id"
USERS ||--o{ LOGS : "id <- user_id"
MINIGAMES ||--o{ MINIGAME_MATCHES : "id <- minigame_id"
USERS ||--o{ MINIGAME_MATCHES : "id <- created_by_user_id"
MINIGAME_MATCHES ||--o{ MATCH_USERS : "id <- match_id"
USERS ||--o{ MATCH_USERS : "id <- user_id"
MINIGAMES ||--o{ MINIGAME_SESSIONS : "id <- minigame_id"
USERS ||--o{ MINIGAME_SESSIONS : "id <- user_id"
MINIGAME_MATCHES o|--o{ MINIGAME_SESSIONS : "id <- match_id"
MINIGAME_SESSIONS ||--o{ MINIGAME_EVENTS : "id <- session_id"
USERS ||--o{ RECOMMENDATIONS : "id <- user_id"
MINIGAMES o|--o{ RECOMMENDATIONS : "id <- minigame_id"
QUIZZES o|--o{ RECOMMENDATIONS : "id <- quiz_id"
USERS ||--o{ USER_MINIGAMES : "id <- user_id"
FAMILIES ||--o{ USER_MINIGAMES : "id <- family_id"
MINIGAMES ||--o{ USER_MINIGAMES : "id <- minigame_id"
USERS ||--o{ YOUTUBE_TOKENS : "id <- user_id"
USERS ||--o{ FAMILIES : "id <- user_id"
USERS ||--o{ FAMILIES : "id <- family_admin"
%% Inferred only: indexed column, but no actual FK constraint in dump
USERS ||--o{ AI_ATTITUDES : "inferred: id <- user_id"
Download the Postman collection
- Open Postman
- Click Import
- Drag & Drop file (or select it)
- Set:
- baseUrl (e.g. http://localhost:3000) - token after login
POST /login- User login (returns JWT token)
GET /users- Get all usersPOST /users- Create new userGET /users/:id- Get user detail (requires auth)PATCH /users/:id- Update user (requires auth)OPTIONS /users- Get allowed methodsOPTIONS /users/:id- Get allowed methods
GET /admin- Admin dashboard (requires auth + admin role)GET /admin/users- Get all users with details (requires auth + admin role)
GET /families- Get all familiesPOST /families- Create familyGET /families/:id- Get family detail (requires auth)PATCH /families/:id- Update familyDELETE /families/:id- Delete familyOPTIONS /families/:id- Get allowed methods
GET /learningModules- Get all learning modules/quizzesPOST /learningModules- Create new learning moduleGET /learningModules/:id- Get learning module detailPUT /learningModules/:id- Update learning moduleDELETE /learningModules/:id- Delete learning moduleOPTIONS /learningModules- Get allowed methodsOPTIONS /learningModules/:id- Get allowed methods
POST /minigame-matches- Create minigame matchPOST /minigame-matches/join- Join a minigame matchGET /minigame-matches/:id/players- Get players in a matchPOST /minigame-matches/:id/start- Start a match (requires auth)POST /minigame-matches/:id/guess- Submit a guess in matchGET /minigame-matches/:id/state- Get match state
POST /minigame-sessions- Create minigame sessionGET /minigame-sessions/:id- Get session detailPOST /minigame-sessions/:id/guess- Submit guess in session
POST /ai/generate- Generate AI themes (requires auth)GET /ai/me- Get user's generated themes (requires auth)
GET /auth/test-callback- Test endpointGET /auth/youtube- Initiate YouTube OAuth flow (requires auth)GET /auth/youtube/callback- OAuth callback from GoogleGET /auth/youtube/status- Get YouTube connection status (requires auth)GET /auth/youtube/detail- Get detailed YouTube data (requires auth)GET /auth/youtube/liked-videos- Get liked videos playlist (requires auth)POST /auth/youtube/liked-videos- Store liked videos to database (requires auth)
GET /users- Get all usersGET /ai_profiles- Get all AI profilesGET /themes- Get all themesGET /families- Get all familiesGET /recommendations- Get all recommendationsGET /logs- Get all logsGET /family_quizzes- Get all family quizzesGET /quizzes- Get all quizzesGET /minigame_matches- Get all minigame matchesGET /minigame_sessions- Get all minigame sessionsGET /youtube_data- Get all YouTube dataOPTIONS /- Get allowed methods
src/
├── api/
├── controllers/
├── documents/
├── hf_ai/
├── middleware/
├── models/
├── routes/
├── services/
├── .env
├── .gitignore
├── database.js
├── index.js
├── package.json
├── package-lock.json
├── README.md
- Host the project on a server (e.g., Heroku, AWS, DigitalOcean, VPS)
- Install node, express and MySQL2 on the server
- Import the database to the server's MySQL instance
- Set environment variables on the server
- Start the server with
node index.jsornpm run dev
This step only works on localhost, so you can test it during development. For production, you would need to set up a proper domain and SSL certificate.
- To verify a user with the YouTube API, they must first be logged in. When a user logs in, this user creates a JWT token. This JWT token is needed for authentication.
- After this, you make a GET request to auth/youtube, in which you receive a link to the verification page and a response message; for this, the JWT token must be provided for authentication.
- Link the user to this URL. You will then go through the typical workflow of linking your Google account with an app.
- When a user is logged in, and this user has already linked with YouTube, you can retrieve data from his/her YouTube channel via a GET request to auth/youtube/detail. The JWT token is also required here.
-In the same way as the channel data, you can retrieve the 10 most recent liked videos of a user by making a GET request to auth/youtube/liked-videos. Here too, the JWT token is required.
-If you do a POST instead of a GET on auth/youtube/liked-videos, it then posts an array of the titles, descriptions, and video tags to the ai_profiles table in the database. Again, the JWT token is required for this.
-This also keeps track of whether the user had previously stored their liked videos. This can be seen from the “stored” value; if it is true, then the user was already known in the database and a new selection of liked videos has been saved.
-There will be another filter for ai_profiles that allows you to filter by tags, so that you can overwhelm a user with the number of tags attached to videos that an AI can have access to.
The application generates user interests (themes) based on YouTube data linked to a user. The data is stored in the ai_profiles table and contains information about videos a user has liked. This data is then analyzed by an AI model via Hugging Face (CohereLabs/tiny-aya-water). The model generates themes from this, which are stored in the themes table. These themes represent the user's interests and preferences.
-
Examples of generated themes:
• favorite movie
• movie genre
• music genre
• artist
• favorite color
• clothing style
• vacation country
The AI_PROFILES table contains YouTube data from the user. It forms the input for the AI analysis.
erDiagram
AI_PROFILES {
bigint id PK
bigint user_id FK
text liked_video_titles
text liked_video_descriptions
text liked_video_tags
datetime created_at
}
The THEMES table contains the generated interests of the user.
erDiagram
THEMES {
bigint id PK
bigint profile_id FK
text movie
text movie_genre
text artist
text food
text place
text music
text music_genre
text holiday_country
text clothing_style
text animal
text color
timestamp created_at
}
For the analysis of user data, the following is used:
- Model:
CohereLabs/tiny-aya-water
This model receives profile data and generates a JSON object with themes.
- Example prompt:
You are an assistant that converts user interests into themes.
Analyze the following ai_profile and return only valid JSON.
Use these keys:
movie
movie_genre
artist
food
place
music
music_genre
holiday_country
clothing_style
animal
color
{
"movie": "Harry Potter",
"movie_genre": "fantasy",
"artist": "Taylor Swift",
"food": "pizza",
"place": "beach",
"music": "pop",
"music_genre": "pop",
"holiday_country": "Italy",
"clothing_style": "casual",
"animal": "cat",
"color": "blue"
}Generates themes based on the AI profile.
- User is logged in
- req.user.id is retrieved
- AI profile is retrieved from the database
- Profile data is sent to Hugging Face
- AI generates themes
- Themes are saved in themes
POST /ai/generate
{
"message": "Themes generated",
"themes": {
"movie": "Harry Potter",
"movie_genre": "fantasy",
"artist": "Taylor Swift"
}
}Retrieves the generated themes of the logged-in user.
GET /themes?id=[PROFILE_ID]
• Retrieve req.user.id
• Find profile
• Retrieve themes
{
"profile_id": 1,
"movie": "Harry Potter",
"music_genre": "pop",
"color": "blue"
}The themeGenerate contains the business logic.
| Function | Description |
|---|---|
getAiProfile() |
Retrieves the AI profile |
generateThemesFromProfile() |
Performs AI-based analysis |
saveThemes() |
Persists generated themes |
generateThemesForUser() |
Executes the full theme generation flow |
For database interaction, mysql2 is used.
await db.query(
`INSERT INTO themes SET ?, timestamp = NOW()`,
[
{
profile_id: profileId,
...themes
}
]
);The following security measures are implemented:
API tokens and database credentials are stored in a .env file.
Example:
HF_TOKEN=xxxxx
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=password
DB_NAME=projectEndpoints use an authentication middleware that sets req.user.
-
req.user.id identifies which user is performing the request.
-
This ensures actions are always tied to an authenticated user.
The application includes basic error handling.
| Error | Response Code |
|---|---|
| Profile not found | 404 |
| Invalid AI response | 500 |
| Database error | 500 |
if (!profile) {
return res.status(404).json({
error: "AI profile not found."
});
}The following enhancements are possible:
The AI can be extended to analyze YouTube data, such as:
- Watched videos
- Subscriptions
- Playlists
This data can be incorporated into the AI prompt to improve personalization.
The current model (Tiny-Aya-Water) is relatively small. In the future, it can be replaced with more advanced models, such as:
- Llama 3
- Mistral
- OpenAI models
This can significantly improve the quality of theme analysis.
To reduce costs and latency, caching can be introduced:
- Redis for fast data access
- Storing AI responses to avoid repeated processing
We've already implemented the functionality to use API keys for authentication. This can be enabled in the future to allow third-party applications to access the theme generation service securely.
The AI Theme Generator:
- Collects user data
- Creates an AI profile
- Analyzes the profile using a Hugging Face model
- Generates themes
- Stores the themes in the database
- Exposes the themes via an API
This system enables the generation of personalized insights based on user behavior.
- Missing or Incomplete .env File, User misses variables or forgets to create .env entirely, leading to application failure.
- Database Connection Failures, Incorrect credentials or database server issues can prevent the app from connecting to the database.
- Node.js Version Incompatibility, Running the app on an unsupported Node.js version can cause unexpected errors.
- Schema Import Problems, Errors during database import (e.g., syntax errors, missing tables) can lead to a non-functional database.
- Existing Data Conflicts, If the database already contains data that conflicts with the expected schema (e.g., duplicate entries), it can cause issues during app operation.
- Youtube OAuth Failures, Users may encounter issues during the YouTube OAuth flow, such as denied permissions or callback errors.
- Hugging Face API Issues, Problems with the Hugging Face API (e.g., rate limits, downtime) can disrupt theme generation.
- JWT Token Issues, Expired or malformed JWT tokens can lead to authentication failures.
- Port Conflicts, If port 8000 is already in use, the app will fail to start.
- API Key Middleware Bug, If the API key middleware is enabled but not properly configured, it can block all requests or allow unauthorized access.
- Missing Accept Header, If the client does not send an Accept header, the server may not know how to respond properly.
- Large Payload Issues, Sending large requests (e.g., large AI profiles) may cause timeouts or memory issues.
- Relative Path Problems, If the env file is put in the wrong directory, or the app is run through linux, it may not be able to find the .env file due to path issues.
- Package Installation Failures, Issues during npm install (e.g., network problems, incompatible package versions) can prevent the app from running.
- Missing Optional Dependencies, If optional dependencies (e.g., for AI integration) are not installed, certain features may not work.
- Concurrent YouTube Data Fetching, If multiple requests to fetch YouTube data for the same user occur simultaneously, it may lead to race conditions and inconsistent database state.
- Partial Data Storage, If an error occurs while saving AI profiles or themes, it may result in incomplete data being stored in the database.





