This document provides detailed information about the OpenSite Analytics database schema.
OpenSite Analytics uses a relational database schema designed for efficient analytics data storage and retrieval. The default database is SQLite, with support for PostgreSQL and MySQL.
┌─────────────┐
│ Users │
├─────────────┤
│ id (PK) │
│ email │
│ password │
│ created_at │
│ is_active │
└─────────────┘
│ 1
│
│ N
┌─────────────┐
│ Sites │
├─────────────┤
│ id (PK) │
│ name │
│ domain │
│ site_key │
│ api_key │
│ owner_id(FK)│
│ created_at │
│ is_active │
└─────────────┘
│ 1
│
│ N
┌─────────────────────────────────────────────────┐
│ PageViews & Events │
├─────────────────────────────────────────────────┤
│ id (PK) │
│ site_id (FK) │
│ session_id │
│ url / event_name │
│ user_agent / event_data │
│ ip_address │
│ country │
│ created_at │
└─────────────────────────────────────────────────┘
Stores user account information.
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | Integer | PRIMARY KEY, AUTO INCREMENT | Unique user identifier |
| String(255) | UNIQUE, NOT NULL | User email address | |
| password_hash | String(255) | NOT NULL | Bcrypt hashed password |
| created_at | DateTime | DEFAULT CURRENT_TIMESTAMP | Account creation timestamp |
| is_active | Boolean | DEFAULT TRUE | Account status |
Indexes:
email (unique)Relationships:
Stores website tracking configurations.
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | Integer | PRIMARY KEY, AUTO INCREMENT | Unique site identifier |
| name | String(255) | NOT NULL | Site display name |
| domain | String(255) | UNIQUE, NOT NULL | Site domain name |
| site_key | String(64) | UNIQUE, NOT NULL | Public tracking key |
| api_key | String(64) | UNIQUE, NOT NULL | Private API key |
| owner_id | Integer | FOREIGN KEY, NOT NULL | User owner reference |
| created_at | DateTime | DEFAULT CURRENT_TIMESTAMP | Site creation timestamp |
| is_active | Boolean | DEFAULT TRUE | Site tracking status |
Indexes:
domain (unique)site_key (unique)api_key (unique)owner_idRelationships:
Stores individual page view events.
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | Integer | PRIMARY KEY, AUTO INCREMENT | Unique page view identifier |
| site_id | Integer | FOREIGN KEY, NOT NULL | Site reference |
| session_id | String(255) | INDEXED | Session identifier |
| url | Text | NOT NULL | Page URL |
| title | String(255) | Page title | |
| referrer | Text | Referrer URL | |
| user_agent | Text | Browser user agent | |
| ip_address | String(45) | IPv4 or IPv6 address | |
| country | String(2) | ISO country code | |
| created_at | DateTime | DEFAULT CURRENT_TIMESTAMP, INDEXED | Timestamp |
Indexes:
site_idsession_idcreated_at(site_id, created_at)Relationships:
Stores custom event tracking data.
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | Integer | PRIMARY KEY, AUTO INCREMENT | Unique event identifier |
| site_id | Integer | FOREIGN KEY, NOT NULL | Site reference |
| session_id | String(255) | INDEXED | Session identifier |
| event_name | String(255) | NOT NULL, INDEXED | Event name |
| event_data | JSON | Custom event properties | |
| created_at | DateTime | DEFAULT CURRENT_TIMESTAMP, INDEXED | Timestamp |
Indexes:
site_idsession_idevent_namecreated_at(site_id, created_at)Relationships:
Stores user session information.
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | Integer | PRIMARY KEY, AUTO INCREMENT | Unique session identifier |
| site_id | Integer | FOREIGN KEY, NOT NULL | Site reference |
| session_id | String(255) | UNIQUE, NOT NULL | Session identifier |
| started_at | DateTime | DEFAULT CURRENT_TIMESTAMP | Session start time |
| ended_at | DateTime | Session end time | |
| page_views_count | Integer | DEFAULT 0 | Total page views in session |
Indexes:
site_idsession_id (unique)Relationships:
Stores conversion goal definitions.
| Column | Type | Constraints | Description |
|---|---|---|---|
| id | Integer | PRIMARY KEY, AUTO INCREMENT | Unique goal identifier |
| site_id | Integer | FOREIGN KEY, NOT NULL | Site reference |
| name | String(255) | NOT NULL | Goal display name |
| description | Text | Goal description | |
| goal_type | String(50) | NOT NULL | 'pageview' or 'event' |
| target_value | String(255) | Target URL or event name | |
| created_at | DateTime | DEFAULT CURRENT_TIMESTAMP | Goal creation timestamp |
Indexes:
site_idgoal_typeRelationships:
ON UPDATE: RESTRICT
PageViews.site_id → Sites.id
ON UPDATE: RESTRICT
Events.site_id → Sites.id
ON UPDATE: RESTRICT
Sessions.site_id → Sites.id
ON UPDATE: RESTRICT
Goals.site_id → Sites.id
All required fields have NOT NULL constraints as indicated in the table schemas.
Old data is automatically cleaned up based on the DATA_RETENTION_DAYS configuration (default: 90 days).
The background scheduler runs a cleanup task that:
# In models.py
class Site(Base):
# ... existing columns
new_column = Column(String(255))
# Run migration
python3 migrate.py
# In models.py
class NewTable(Base):
__tablename__ = "new_table"
id = Column(Integer, primary_key=True)
# ... other columns
# In init_db.py
Base.metadata.create_all(bind=engine)
# Backup
cp analytics.db analytics.db.backup.$(date +%Y%m%d)
# Restore
cp analytics.db.backup.YYYYMMDD analytics.db
# Backup
pg_dump -U user -d opensite > backup.sql
# Restore
psql -U user -d opensite < backup.sql
# Backup
mysqldump -u user -p opensite > backup.sql
# Restore
mysql -u user -p opensite < backup.sql