PHP 7.4.33
Preview: database-schema.sql Size: 7.20 KB
/var/www/snow-ecom.wpress.dk/httpdocs/database-schema.sql
-- User Action Logging Database Schema
-- This schema provides comprehensive logging for user actions in the booking system

-- Create the user_actions_log table
CREATE TABLE user_actions_log (
    id BIGINT IDENTITY(1,1) PRIMARY KEY,
    user_id NVARCHAR(255) NOT NULL,
    user_email NVARCHAR(255) NOT NULL,
    action NVARCHAR(50) NOT NULL CHECK (action IN ('SAVE', 'SAVE_AND_SEND', 'RESEND', 'PREVIEW', 'EDIT')),
    entity_type NVARCHAR(50) NOT NULL CHECK (entity_type IN ('CUSTOMER', 'PARTICIPANT', 'PAYMENT', 'PRODUCT', 'PDF', 'EMAIL')),
    entity_id NVARCHAR(255) NOT NULL,
    booking_id NVARCHAR(255) NOT NULL,
    page_id NVARCHAR(255) NOT NULL,
    brand NVARCHAR(100) NOT NULL,
    language NVARCHAR(10) NOT NULL,
    action_data NVARCHAR(MAX), -- JSON data of what was changed
    timestamp DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
    ip_address NVARCHAR(45), -- IPv6 compatible
    user_agent NVARCHAR(500),
    session_id NVARCHAR(255),
    status NVARCHAR(20) NOT NULL CHECK (status IN ('SUCCESS', 'FAILED', 'PENDING')) DEFAULT 'SUCCESS',
    error_message NVARCHAR(MAX),
    version NVARCHAR(100),
    
    -- Indexes for better query performance
    INDEX idx_user_actions_log_user_id (user_id),
    INDEX idx_user_actions_log_user_email (user_email),
    INDEX idx_user_actions_log_booking_id (booking_id),
    INDEX idx_user_actions_log_action (action),
    INDEX idx_user_actions_log_entity_type (entity_type),
    INDEX idx_user_actions_log_timestamp (timestamp),
    INDEX idx_user_actions_log_status (status),
    INDEX idx_user_actions_log_user_timestamp (user_id, timestamp),
    INDEX idx_user_actions_log_booking_timestamp (booking_id, timestamp)
);

-- Create a view for common queries
CREATE VIEW v_user_actions_summary AS
SELECT 
    user_id,
    user_email,
    booking_id,
    action,
    entity_type,
    status,
    COUNT(*) as action_count,
    MIN(timestamp) as first_action,
    MAX(timestamp) as last_action,
    AVG(DATEDIFF(MINUTE, LAG(timestamp) OVER (PARTITION BY booking_id ORDER BY timestamp), timestamp)) as avg_time_between_actions
FROM user_actions_log
GROUP BY user_id, user_email, booking_id, action, entity_type, status;

-- Create a view for failed actions
CREATE VIEW v_failed_actions AS
SELECT 
    user_id,
    user_email,
    booking_id,
    action,
    entity_type,
    error_message,
    timestamp
FROM user_actions_log
WHERE status = 'FAILED'
ORDER BY timestamp DESC;

-- Create a view for user activity summary
CREATE VIEW v_user_activity_summary AS
SELECT 
    user_id,
    user_email,
    COUNT(*) as total_actions,
    COUNT(CASE WHEN status = 'SUCCESS' THEN 1 END) as successful_actions,
    COUNT(CASE WHEN status = 'FAILED' THEN 1 END) as failed_actions,
    COUNT(DISTINCT booking_id) as unique_bookings,
    MIN(timestamp) as first_action_date,
    MAX(timestamp) as last_action_date,
    DATEDIFF(DAY, MIN(timestamp), MAX(timestamp)) as days_active
FROM user_actions_log
GROUP BY user_id, user_email;

-- Create a stored procedure for cleaning old logs
CREATE PROCEDURE sp_cleanup_old_logs
    @days_to_keep INT = 90
AS
BEGIN
    SET NOCOUNT ON;
    
    DECLARE @cutoff_date DATETIME2 = DATEADD(DAY, -@days_to_keep, GETUTCDATE());
    
    DELETE FROM user_actions_log 
    WHERE timestamp < @cutoff_date;
    
    SELECT @@ROWCOUNT as deleted_rows;
END;

-- Create a stored procedure for getting user action history
CREATE PROCEDURE sp_get_user_action_history
    @user_email NVARCHAR(255),
    @start_date DATETIME2 = NULL,
    @end_date DATETIME2 = NULL,
    @action_type NVARCHAR(50) = NULL,
    @entity_type NVARCHAR(50) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    
    SELECT 
        id,
        user_id,
        user_email,
        action,
        entity_type,
        entity_id,
        booking_id,
        page_id,
        brand,
        language,
        action_data,
        timestamp,
        ip_address,
        user_agent,
        session_id,
        status,
        error_message,
        version
    FROM user_actions_log
    WHERE user_email = @user_email
        AND (@start_date IS NULL OR timestamp >= @start_date)
        AND (@end_date IS NULL OR timestamp <= @end_date)
        AND (@action_type IS NULL OR action = @action_type)
        AND (@entity_type IS NULL OR entity_type = @entity_type)
    ORDER BY timestamp DESC;
END;

-- Create a stored procedure for getting booking action history
CREATE PROCEDURE sp_get_booking_action_history
    @booking_id NVARCHAR(255),
    @start_date DATETIME2 = NULL,
    @end_date DATETIME2 = NULL
AS
BEGIN
    SET NOCOUNT ON;
    
    SELECT 
        id,
        user_id,
        user_email,
        action,
        entity_type,
        entity_id,
        booking_id,
        page_id,
        brand,
        language,
        action_data,
        timestamp,
        ip_address,
        user_agent,
        session_id,
        status,
        error_message,
        version
    FROM user_actions_log
    WHERE booking_id = @booking_id
        AND (@start_date IS NULL OR timestamp >= @start_date)
        AND (@end_date IS NULL OR timestamp <= @end_date)
    ORDER BY timestamp DESC;
END;

-- Create a function to get action statistics
CREATE FUNCTION fn_get_action_statistics
(
    @start_date DATETIME2,
    @end_date DATETIME2
)
RETURNS TABLE
AS
RETURN
(
    SELECT 
        action,
        entity_type,
        status,
        COUNT(*) as action_count,
        COUNT(DISTINCT user_id) as unique_users,
        COUNT(DISTINCT booking_id) as unique_bookings
    FROM user_actions_log
    WHERE timestamp BETWEEN @start_date AND @end_date
    GROUP BY action, entity_type, status
);

-- Insert sample data for testing (optional)
-- INSERT INTO user_actions_log (user_id, user_email, action, entity_type, entity_id, booking_id, page_id, brand, language, action_data, status)
-- VALUES 
-- ('user123', 'user@example.com', 'SAVE', 'CUSTOMER', 'booking123', 'booking123', 'page1', 'brand1', 'en', '{"customerData": {"name": "John Doe"}}', 'SUCCESS'),
-- ('user123', 'user@example.com', 'SAVE_AND_SEND', 'PDF', 'booking123', 'booking123', 'page1', 'brand1', 'en', '{"pdfVersion": "1.0"}', 'SUCCESS');

-- Comments on the schema design:
/*
1. **Primary Key**: Auto-incrementing BIGINT for performance and scalability
2. **User Identification**: Both user_id and user_email for flexibility
3. **Action Types**: Enumerated values for consistency and performance
4. **Entity Types**: Categorized by what type of data was modified
5. **Action Data**: JSON field to store detailed information about changes
6. **Timestamps**: UTC timestamps for consistency across timezones
7. **Status Tracking**: Success/failure status with error messages
8. **Audit Trail**: IP address, user agent, and session tracking
9. **Indexes**: Optimized for common query patterns
10. **Views**: Pre-built queries for common reporting needs
11. **Stored Procedures**: Encapsulated business logic for data access
12. **Data Retention**: Procedure for cleaning old logs
13. **Statistics**: Function for generating action statistics

Recommended data retention policy:
- Keep logs for 90 days by default
- Archive older logs to separate storage if needed
- Consider data privacy regulations (GDPR, etc.)

Performance considerations:
- Monitor index usage and adjust as needed
- Consider partitioning by date for large datasets
- Regular maintenance of statistics and indexes
*/ 

Directory Contents

Dirs: 5 × Files: 23
Name Size Perms Modified Actions
.git DIR
- drwxr-xr-x 2026-05-08 11:22:09
Edit Download
.next DIR
- drwxr-xr-x 2026-05-08 11:23:38
Edit Download
- drwxr-xr-x 2026-05-08 11:23:03
Edit Download
public DIR
- drwxr-xr-x 2026-05-08 11:22:09
Edit Download
src DIR
- drwxr-xr-x 2026-05-08 11:22:09
Edit Download
1.20 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
124 B lrw-r--r-- 2026-05-08 11:22:09
Edit Download
571 B lrw-r--r-- 2026-05-08 11:22:09
Edit Download
424 B lrw-r--r-- 2026-05-08 11:22:09
Edit Download
445 B lrw-r--r-- 2026-05-08 11:22:09
Edit Download
5.95 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
6.76 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
7.20 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
4.44 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
393 B lrw-r--r-- 2026-05-08 11:22:09
Edit Download
7.41 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
3.81 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
9.71 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
14.06 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
1.43 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
262 B lrw-r--r-- 2026-05-08 11:23:23
Edit Download
325 B lrw-r--r-- 2026-05-08 11:22:09
Edit Download
339.87 KB lrw-r--r-- 2026-05-08 11:23:02
Edit Download
2.74 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
82 B lrw-r--r-- 2026-05-08 11:22:09
Edit Download
6.09 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
2.09 KB lrw-r--r-- 2026-05-08 11:22:09
Edit Download
602 B lrw-r--r-- 2026-05-08 11:22:09
Edit Download
If ZipArchive is unavailable, a .tar will be created (no compression).