Database Architecture

The eTeamups Platform uses MongoDB 7 as its primary data store, accessed through Mongoose 8.15.0 as the ODM layer. All models, schemas, and DTOs (TypeScript interfaces) are centralised in the services/store/ directory and shared across all services.

MongooseClient Singleton

Database connections are managed by the MongooseClient singleton class in libs/mongo/src/mongooseClient.ts. Key characteristics:

  • Singleton pattern: MongooseClient.getInstance() returns the same connection across all callers.
  • Auto-connection: The BaseModel constructor calls MongooseClient.getInstance() on every model instantiation, ensuring the connection is established before any query.
  • Connection string: Read from MONGODB_URL or DATABASE_URL environment variable.
  • Timeout: serverSelectionTimeoutMS is set to 5000 ms.
  • Event listeners: Logs error, disconnected, and reconnected events.
class MongooseClient {
    private static instance: mongoose.Connection;

    static async getInstance(): Promise<mongoose.Connection> {
        if (!MongooseClient.instance) {
            await mongoose.connect(connectionString, {
                serverSelectionTimeoutMS: 5000
            });
            MongooseClient.instance = mongoose.connection;
        }
        return MongooseClient.instance;
    }
}

BaseModel Pattern

Every model class extends BaseModel<T>, which provides a standard set of CRUD operations and automatic field population.

Location: services/store/src/model/BaseModel.ts

Automatic Fields

On every create() call, BaseModel automatically sets:

Field Value
id UUID v4 (via uuid package)
createdAt Current timestamp
updatedAt Current timestamp

Provided Methods

Method Signature Description
create create(payload: Partial<T>) Insert a new document with auto-generated id and timestamps
findOne findOne(filter: FilterQuery<T>) Find a single matching document
findMany findMany(filter: FilterQuery<T>) Find all matching documents, sorted by createdAt descending
delete delete(filter: FilterQuery<T>) Delete all matching documents (deleteMany)
patch patch(filter: FilterQuery<T>, payload: UpdateQuery<T>) Update all matching documents (updateMany)

Example Usage

export class AccountModel extends BaseModel<IAccount> {
    constructor() {
        super(AccountMongooseModel);
    }

    async find(payload: Partial<IAccount>): Promise<IAccount | null> {
        return this.findOne({ emailAddress: payload.emailAddress });
    }
}

Collections and Schemas

The platform uses 16 MongoDB collections. Each collection has a corresponding TypeScript interface (DTO) and Mongoose schema.


accounts

Stores user account records.

Interface (IAccount):

interface IAccount extends Document {
    id: string;
    firstName: string;
    lastName: string;
    emailAddress: string;
    role: 'GHOST' | 'ADMIN' | 'EDITOR' | 'VIEWER';
    status: 'ACTIVE' | 'PENDING' | 'BLOCKED' | 'REPORTED';
    createdAt: Date;
    updatedAt: Date;
}

Schema notes: id defaults to UUID v4. role defaults to 'VIEWER'. String fields firstName and lastName are trimmed.


otps

Stores one-time passwords for email-based authentication.

Interface (IOtp):

interface IOtp extends Document {
    id: string;
    emailAddress: string;
    otp: string;
    accountId: string;
    status: 'PENDING' | 'VERIFIED' | 'EXPIRED' | 'USED';
    codeChallenge: string;
    createdAt: Date;
    updatedAt: Date;
    expiresAt: Date;
}

Schema notes: status is an enum. codeChallenge stores the PKCE challenge for verification. expiresAt is set to 5 minutes from creation. Previous OTPs for the same email are deleted before a new one is created.


tokens

Stores refresh tokens for JWT-based authentication.

Interface (IToken):

interface IToken extends Document {
    id: string;
    token: string;
    phone_number_id: string;
    expiresAt: Date;
    createdAt: Date;
    updatedAt: Date;
}

Schema notes: The phone_number_id field references the account ID (legacy naming from when the system used phone numbers).


organisations

Stores organisation configuration and settings.

Interface (IOrganisation):

interface IOrganisation extends Document {
    id: string;
    createdAt: Date;
    updatedAt: Date;
    algorithmVersion: 'v1' | 'v2';
    genderInputOnRegister: boolean;
    includeMatchUserInTeam: boolean;
    isLocationPriority: boolean;
    isPublic: boolean;
    licenses: number;
    logo?: string;
    name: string;
    productExpireTimestamp?: Date;
    sampleAddTimestamp?: Date;
    showMatches: boolean;
    templatePrefix?: string;
    urlName: string;
    userChange: boolean;
    workstyleWeight?: number;
}

Schema notes: name is unique with a max length of 100. id defaults to UUID v4. The schema uses Mongoose timestamps: true and has a pre-save hook to ensure id is set.


teammates

Stores individual teammate profiles within organisations.

Interface (ITeammates):

interface ITeammates extends Document {
    _id: string;
    title: string;
    firstName: string;
    lastName: string;
    gender: 'MALE' | 'FEMALE';
    emailAddress: string;
    phoneNumber: string;
    location_id: string;
    profilePhoto: string;
    organisation_id: string;
    token: string;
    accountActicationAt: Date;
    lastLogin: Date;
    createdAt: Date;
    updatedAt: Date;
}

Schema notes: gender is an enum. location_id and organisation_id are string references.


teams

Stores team definitions within organisations.

Interface (ITeam):

interface ITeam extends Document {
    _id: string;
    organisation_id: string;
    teamName: string;
    teamDescription: string;
    managers: string[];
    createdAt: Date;
    updatedAt: Date;
}

Schema notes: managers is an array of string IDs.


countries

Master data catalogue of countries.

Interface (ICountry):

interface ICountry {
    id?: string;
    createdAt: Date;
    updatedAt: Date;
    code: string;
    deleted: boolean;
    name?: string;
    description?: string;
}

industries

Master data catalogue of industries.

Interface (IIndustry):

interface IIndustry {
    id?: string;
    createdAt: Date;
    updatedAt: Date;
    name: string;
    orderBy: number;
    description?: string;
}

functions

Master data catalogue of job functions/roles.

Interface (IFunction):

interface IFunction {
    id?: string;
    name: string;
    orderBy: number;
    createdAt: Date;
    updatedAt: Date;
    description?: string;
}

educationlevels

Master data catalogue of education levels.

Interface (IEducationLevel):

interface IEducationLevel {
    id?: string;
    createdAt: Date;
    updatedAt: Date;
    aliases?: string;
    name: string;
    orderIndex: number;
    rank?: number;
    description?: string;
}

studymajors

Master data catalogue of study majors.

Interface (IStudyMajor):

interface IStudyMajor {
    id?: string;
    name: string;
    description?: string;
    createdAt: Date;
    updatedAt: Date;
}

locations

Master data catalogue of physical locations.

Interface (ILocation):

interface ILocation {
    id?: string;
    createdAt: Date;
    updatedAt: Date;
    linkedIdCode?: number;
    name: string;
    country_id: string;
    address: string;
    city: string;
    state: string;
    postalCode: string;
    latitude?: number;
    longitude?: number;
    isActive?: boolean;
    description?: string;
}

Schema notes: country_id is a string reference to the countries collection.


skills

Master data catalogue of skills.

Interface (ISkill):

interface ISkill {
    id: string;
    name: string;
    description?: string;
    orderBy: number;
    createdAt: Date;
    updatedAt: Date;
}

questionanswers

Stores answers linked to assessment questions.

Interface (IQuestionAnswer):

interface IQuestionAnswer {
    id?: number;
    createdAt: Date;
    updatedAt: Date;
    orderIndex: number;
    text?: string;
    value: number;
    questionId: number;
}

userquestiongroupscores

Stores aggregated scores for user question groups.

Interface (IUserQuestionGroupScore):

interface IUserQuestionGroupScore extends Document {
    id: number;
    createdAT: Date;
    updateAt: Date;
    averageScore?: number;
    publicDisplay: boolean;
    questionGroup_id: number;
    user_id: number;
}

apilogs

Stores API request/response logs for auditing and debugging.

Interface (IAPILog):

interface IAPILog extends Document {
    id: string;
    rawHeaders: string[];
    url: string;
    method: string;
    remoteAddress: string;
    remoteFamily: string;
    httpVersion: string;
    body: any;
    params: any;
    query: any;
    startTime: Date;
    endTime: Date;
    processingTime: number;
    createdAt: Date;
    updatedAt: Date;
}

Schema notes: id defaults to UUID v4. body, params, and query are stored as generic objects.


Entity Relationship Diagram

erDiagram ACCOUNTS { string id PK string firstName string lastName string emailAddress string role string status date createdAt date updatedAt } OTPS { string id PK string emailAddress string otp string accountId FK string status string codeChallenge date expiresAt date createdAt date updatedAt } TOKENS { string id PK string token string phone_number_id FK date expiresAt date createdAt date updatedAt } ORGANISATIONS { string id PK string name string urlName string algorithmVersion boolean isPublic number licenses string logo date createdAt date updatedAt } TEAMS { string _id PK string organisation_id FK string teamName string teamDescription date createdAt date updatedAt } TEAMMATES { string _id PK string firstName string lastName string emailAddress string gender string organisation_id FK string location_id FK date createdAt date updatedAt } COUNTRIES { string id PK string code string name boolean deleted } LOCATIONS { string id PK string name string country_id FK string address string city string state string postalCode number latitude number longitude } INDUSTRIES { string id PK string name number orderBy } FUNCTIONS { string id PK string name number orderBy } EDUCATIONLEVELS { string id PK string name number orderIndex number rank } STUDYMAJORS { string id PK string name } SKILLS { string id PK string name number orderBy } QUESTIONANSWERS { number id PK number questionId string text number value number orderIndex } USERQUESTIONGROUPSCORES { number id PK number questionGroup_id number user_id FK number averageScore boolean publicDisplay } APILOGS { string id PK string url string method number processingTime date startTime date endTime } ACCOUNTS ||--o{ OTPS : "has" ACCOUNTS ||--o{ TOKENS : "has" ORGANISATIONS ||--o{ TEAMS : "contains" ORGANISATIONS ||--o{ TEAMMATES : "contains" COUNTRIES ||--o{ LOCATIONS : "has" LOCATIONS ||--o{ TEAMMATES : "assigned to" TEAMS }o--o{ TEAMMATES : "members (via managers array)"

File Organisation

services/store/src/
  dto/
    IAccount.ts
    IOtp.ts
    IToken.ts
    IOrgainisation.ts
    ITeam.ts
    ITeammates.ts
    ICountry.ts
    IIndustry.ts
    IFunction.ts
    IEducationLevel.ts
    IStudyMajor.ts
    ILocation.ts
    ISkill.ts
    IQuestionAnswer.ts
    IUserQuestionGroupScore.ts
    IAPILog.ts
  schema/
    AccountSchema.ts
    OtpSchema.ts
    TokenSchema.ts
    OrganisationSchema.ts
    TeamSchema.ts
    TeammatesSchema.ts
    CountrySchema.ts
    IndustrySchema.ts
    FunctionSchema.ts
    EducationLevelSchema.ts
    StudyMajorSchema.ts
    LocationSchema.ts
    SkillSchema.ts
    QuestionAnswerSchema.ts
    UserQuestionGroupScoreSchema.ts
    APILogSchema.ts
  model/
    BaseModel.ts
    AccountModel.ts
    OtpModel.ts
    TokenModel.ts
    OrganisationModel.ts
    TeamModel.ts
    TeammatesModel.ts
    CountryModel.ts
    IndustryModel.ts
    FunctionModel.ts
    EducationLevelModel.ts
    StudyMajorModel.ts
    LocationModel.ts
    SkillModel.ts
    QuestionAnswerModel.ts
    UserQuestionGroupScoreModel.ts
    APILogModel.ts

Indexing Strategy

The current schema definitions rely primarily on MongoDB’s default _id index plus a few explicit constraints:

Collection Index / Constraint
accounts id (UUID, set on create)
organisations name (unique, maxlength 100), id (UUID)
otps Queried by accountId + otp + status + expiresAt
tokens Queried by token + expiresAt

For production workloads, consider adding compound indexes on the frequently queried filter combinations listed above to improve query performance.