tito-insight-package
v1.0.1
Published
NestJS Activity Logger with Drizzle ORM - Track authentication events and page visits with comprehensive analytics
Maintainers
Readme
Tito Insight Package
A powerful NestJS activity logging module with Drizzle ORM integration. Track authentication events, page visits, and user behavior with comprehensive analytics dashboards.
Features
- 🔐 Authentication Logging - Track login attempts, logouts, registrations, and password changes
- 📊 Page Visit Tracking - Monitor user navigation, response times, and page performance
- 🌍 Geographic Analytics - IP-based location tracking and suspicious activity detection
- 📈 User Behavior Analytics - Engagement metrics, most active users, and user journey analysis
- 🔍 Security Analytics - Brute force detection, IP reputation scoring, and suspicious locations
- ⏰ Temporal Analytics - Peak usage hours, weekly patterns, and activity trends
- 🗑️ Data Retention - Automated log cleanup with configurable retention policies
- 🔑 RBAC Integration - Optional role-based access control for analytics endpoints
- 🎯 Flexible Configuration - Support for sync/async configuration, custom auth guards, and databases
Installation
npm install tito-insight-packagePeer Dependencies
{
"@nestjs/common": "^10.0.0 || ^11.0.0",
"@nestjs/core": "^10.0.0 || ^11.0.0",
"@nestjs/platform-express": "^10.0.0",
"reflect-metadata": "^0.1.13 || ^0.2.0"
}Database Setup
PostgreSQL Tables
Run these SQL commands to create the required tables:
-- Create ENUM types
CREATE TYPE auth_activity_event AS ENUM (
'LOGIN', 'LOGIN_FAILED', 'LOGOUT', 'LOGOUT_ALL', 'REGISTER',
'MFA_CHALLENGE', 'MFA_SUCCESS', 'MFA_FAILURE',
'PASSWORD_RESET_REQUEST', 'PASSWORD_RESET_COMPLETE',
'EMAIL_VERIFY', 'TOKEN_REFRESH'
);
CREATE TYPE auth_activity_status AS ENUM ('success', 'failure');
-- Create auth_activity_logs table
CREATE TABLE auth_activity_logs (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36),
username VARCHAR(255) NOT NULL,
event_type auth_activity_event NOT NULL,
login_type VARCHAR(50),
status auth_activity_status NOT NULL,
attempts INTEGER DEFAULT 1,
ip_address VARCHAR(45),
user_agent TEXT,
location JSONB,
metadata JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
-- Create page_activity_logs table
CREATE TABLE page_activity_logs (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36),
method VARCHAR(10) NOT NULL,
path VARCHAR(500) NOT NULL,
route_name VARCHAR(255),
status_code INTEGER NOT NULL,
response_time INTEGER,
ip_address VARCHAR(45),
user_agent TEXT,
location JSONB,
referrer VARCHAR(500),
metadata JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
);
-- Create indexes for performance
CREATE INDEX idx_auth_logs_user_id ON auth_activity_logs(user_id);
CREATE INDEX idx_auth_logs_created_at ON auth_activity_logs(created_at);
CREATE INDEX idx_auth_logs_status ON auth_activity_logs(status);
CREATE INDEX idx_page_logs_user_id ON page_activity_logs(user_id);
CREATE INDEX idx_page_logs_created_at ON page_activity_logs(created_at);
CREATE INDEX idx_page_logs_path ON page_activity_logs(path);Quick Start
Basic Configuration
import { Module } from '@nestjs/common';
import { ActivityLoggerModule } from 'tito-insight-package';
@Module({
imports: [
ActivityLoggerModule.forRoot({
database: {
type: 'postgresql',
connectionString: 'postgresql://user:password@localhost:5432/mydb',
},
}),
],
})
export class AppModule {}Full Configuration
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ActivityLoggerModule } from 'tito-insight-package';
@Module({
imports: [
ConfigModule.forRoot(),
ActivityLoggerModule.forRoot({
database: {
type: 'postgresql',
connectionString: process.env.DATABASE_URL!,
ssl: true,
maxConnections: 20,
},
auth: {
enabled: true,
jwtSecret: process.env.JWT_SECRET,
global: true,
},
rbac: {
enabled: true,
superAdminRole: 'admin',
},
logging: {
logLevel: 'debug',
skipPaths: ['/health', '/metrics'],
},
retention: {
autoDeleteEnabled: true,
authLogsRetentionDays: 90,
pageLogsRetentionDays: 60,
},
}),
],
})
export class AppModule {}Async Configuration
@Module({
imports: [
ActivityLoggerModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
database: {
type: 'postgresql',
connectionString: configService.get<string>('DATABASE_URL')!,
},
auth: {
enabled: true,
jwtSecret: configService.get<string>('JWT_SECRET'),
},
}),
}),
],
})
export class AppModule {}Usage
Manual Event Logging
import { Injectable } from '@nestjs/common';
import { ActivityLoggerService, AuthEventLogData } from 'tito-insight-package';
@Injectable()
export class AuthService {
constructor(private readonly activityLogger: ActivityLoggerService) {}
async login(user: any, ipAddress: string, userAgent: string) {
// Your login logic here
const result = await this.validateCredentials(user);
// Log the authentication event
await this.activityLogger.logAuthEvent({
userId: result.user.id,
username: user.username,
eventType: 'LOGIN',
status: result.success ? 'success' : 'failure',
ipAddress,
userAgent,
loginType: 'password',
});
return result;
}
}Decorator-Based Tracking
import { Controller, Post, Body } from '@nestjs/common';
import { TrackActivity } from 'tito-insight-package';
@Controller('auth')
export class AuthController {
@Post('login')
@TrackActivity('User Login')
async login(@Body() loginDto: LoginDto) {
return this.authService.login(loginDto);
}
@Post('logout')
@TrackActivity('User Logout')
async logout() {
return this.authService.logout();
}
}Interceptor-Based Logging
Apply to specific controllers or globally:
import { Controller, UseInterceptors } from '@nestjs/common';
import { ActivityLoggingInterceptor } from 'tito-insight-package';
@Controller('dashboard')
@UseInterceptors(ActivityLoggingInterceptor)
export class DashboardController {
// All routes here will be automatically logged
}Or apply globally in your main.ts:
import { ActivityLoggingInterceptor } from 'tito-insight-package';
app.useGlobalInterceptors(new ActivityLoggingInterceptor(
activityLoggerService,
new Reflector(),
));Skipping Logging
Use the @SkipActivityLog() decorator to skip logging on specific routes:
import { Controller, Get } from '@nestjs/common';
import { SkipActivityLog } from 'tito-insight-package';
@Controller('health')
export class HealthController {
@Get()
@SkipActivityLog()
check() {
return { status: 'ok' };
}
}Analytics API
The package includes a RESTful API for accessing analytics data:
Authentication Logs
// Get auth logs with filters
await activityLogger.queryAuthLogs({
userId: 'user-123',
eventType: 'LOGIN',
status: 'success',
startDate: new Date('2024-01-01'),
endDate: new Date('2024-01-31'),
limit: 100,
offset: 0,
});Page Analytics
// Get page statistics
const stats = await activityLogger.getPageStats('week');
// Get peak usage hours
const peakHours = await activityLogger.getPeakUsageHours('month');
// Get response time analysis
const responseTimes = await activityLogger.getResponseTimeAnalysis('week');User Behavior
// Get most active users
const activeUsers = await activityLogger.getMostActiveUsers(10, 'week');
// Get user journey
const journey = await activityLogger.getUserJourney('user-123', 'month');
// Get user engagement
const engagement = await activityLogger.getUserEngagement('quarter');Security Analytics
// Get suspicious logs
const suspicious = await activityLogger.getSuspiciousLogs(5);
// Get IP reputation
const reputation = await activityLogger.getIpReputation();
// Get brute force analysis
const bruteForce = await activityLogger.getBruteForceAnalysis(60);Geographic Analytics
// Get analytics by location
const byLocation = await activityLogger.getGeographicAnalytics('week');
// Get suspicious locations
const suspiciousLocations = await activityLogger.getSuspiciousLocations(10);Authentication & RBAC
Protecting Analytics Endpoints
Use the built-in guards to protect analytics endpoints:
import { Controller, Get, UseGuards } from '@nestjs/common';
import { Permissions } from 'tito-insight-package';
import { PermissionsGuard } from 'tito-insight-package';
@Controller('analytics')
@UseGuards(PermissionsGuard)
export class AnalyticsController {
@Get('user-stats')
@Permissions('analytics:read')
async getUserStats() {
// Only users with 'analytics:read' permission can access
}
@Get('export')
@Permissions('analytics:export')
async exportData() {
// Only users with 'analytics:export' permission can access
}
}Custom Auth Guard
You can provide your own authentication guard:
import { AuthService } from './auth/auth.service';
import { LocalAuthGuard } from './auth/guards/local-auth.guard';
const customGuard = {
canActivate: async (context) => {
// Your custom auth logic
return true;
};
};
ActivityLoggerModule.forRoot({
database: { /* */ },
auth: {
enabled: true,
guard: customGuard,
},
});Data Retention
Automatically delete old logs based on retention policies:
// Manual cleanup
await activityLogger.deleteOldAuthLogs(90); // Delete logs older than 90 days
await activityLogger.deleteOldPageLogs(60); // Delete logs older than 60 daysThe ActivityLoggerRetentionService runs automatically based on your configuration:
retention: {
autoDeleteEnabled: true,
authLogsRetentionDays: 90,
pageLogsRetentionDays: 60,
}Configuration Options
DatabaseConfig
| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | type | 'postgresql' | 'mysql' | 'sqlite' | Yes | - | Database type | | connectionString | string | Yes | - | Database connection string | | ssl | boolean | No | false | Use SSL connection | | maxConnections | number | No | 10 | Max pool size |
AuthConfig
| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | enabled | boolean | Yes | false | Enable authentication | | jwtSecret | string | No | - | JWT secret key | | guard | any | No | JwtAuthGuard | Custom auth guard | | global | boolean | No | false | Apply globally |
RbacConfig
| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | enabled | boolean | Yes | false | Enable RBAC | | superAdminRole | string | No | 'admin' | Super admin role name | | permissionsGuard | any | No | PermissionsGuard | custom permissions guard |
LoggingConfig
| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | logLevel | 'error' | 'warn' | 'log' | 'debug' | No | 'log' | Logging level | | skipPaths | string[] | No | [] | Paths to skip logging |
RetentionConfig
| Option | Type | Required | Default | Description | |--------|------|----------|---------|-------------| | autoDeleteEnabled | boolean | No | false | Auto-delete old logs | | authLogsRetentionDays | number | No | 90 | Auth logs retention | | pageLogsRetentionDays | number | No | 60 | Page logs retention |
API Endpoints
The module exposes these HTTP endpoints (when controller is included):
Authentication Analytics
GET /activity-logger/auth/stats?range=week- Get auth statisticsGET /activity-logger/auth/logs?limit=100&offset=0- Query auth logsGET /activity-logger/auth/suspicious?threshold=5- Get suspicious logs
Page Analytics
GET /activity-logger/page/stats?range=week- Get page statisticsGET /activity-logger/page/logs?limit=100&offset=0- Query page logs
User Analytics
GET /activity-logger/analytics/engagement?range=week- User engagementGET /activity-logger/analytics/users?limit=10&range=week- Most active usersGET /activity-logger/analytics/journey/:userId?range=week- User journey
Geographic Analytics
GET /activity-logger/analytics/location?range=week- Geographic dataGET /activity-logger/analytics/location/suspicious?threshold=5- Suspicious locations
Security Analytics
GET /activity-logger/analytics/brute-force?timeWindow=60- Brute force analysisGET /activity-logger/analytics/ip-reputation- IP reputation scores
Examples
See the examples/basic-usage directory for a complete NestJS application using this package.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
ISC
Support
For issues and questions, please open an issue on GitHub.
