Skip to content

Data Models

The AV application uses Django ORM with PostgreSQL for transactional data. All models use UUID primary keys and follow a multi-tenant architecture with workspaces and projects.

Architecture Overview

The system implements a multi-tenant SaaS architecture where:

  • Each Workspace is an isolated tenant container
  • Projects belong to workspaces and have specific types (ASO Android, ASO Apple)
  • Users can belong to multiple workspaces with different roles
  • Access control is managed at both workspace and project levels

Core Models

CustomUser

Custom user model extending Django's AbstractUser with UUID primary keys.

Field Type Description
id UUID Primary key
email EmailField Unique email (used for authentication)
username CharField Username
first_name CharField First name
last_name CharField Last name
date_joined DateTimeField Account creation timestamp

Workspace

Main tenant container for multi-tenancy.

Field Type Description
id UUID Primary key
name CharField Workspace name
owner ForeignKey Reference to CustomUser (owner)
created_at DateTimeField Creation timestamp
updated_at DateTimeField Last update timestamp

Methods: - get_projects_for_user(user) - Returns all projects accessible to a user in this workspace

WorkspaceUser

Links users to workspaces with specific roles.

Field Type Description
id UUID Primary key
workspace ForeignKey Reference to Workspace
user ForeignKey Reference to CustomUser
role CharField User role (OWNER, ADMIN, VIEWER)

Role Permissions: - OWNER: Full control over workspace and all projects - ADMIN: Can manage workspace settings and users - VIEWER: Read-only access to workspace

Project

Base project model that can be specialized for different project types.

Field Type Description
id UUID Primary key
name CharField Project name
workspace ForeignKey Reference to Workspace
type CharField Project type (ASO_ANDROID, ASO_APPLE)

Methods: - user_has_access(user) - Returns True if user can access this project

ProjectUserAccess

Grants specific users access to projects within a workspace.

Field Type Description
id UUID Primary key
workspace_user ForeignKey Reference to WorkspaceUser
project ForeignKey Reference to Project
role CharField Project role (ADMIN, VIEWER)

Android ASO Models

AndroidApp

Represents an Android application from Google Play Store.

Field Type Description
id UUID Primary key
name CharField App name
package_id CharField Unique package identifier (e.g., com.example.app)

AndroidAppCountryLanguage

Represents app localization for a specific country and language.

Field Type Description
id UUID Primary key
app ForeignKey Reference to AndroidApp
country CharField ISO 2-letter country code
language CharField ISO language code

AndroidAppKeyword

Keywords tracked for a specific Android app localization.

Field Type Description
id UUID Primary key
acl ForeignKey Reference to AndroidAppCountryLanguage
text CharField Keyword text

ASOAndroidProject

Android ASO project configuration for tracking app performance across multiple markets.

Field Type Description
id UUID Primary key
project OneToOneField Reference to base Project
app ForeignKey Reference to AndroidApp
markets ManyToMany Country-language markets being tracked for this app
keywords ManyToMany Keywords to track across all markets
competitors ManyToMany Competitor app markets to monitor (in same markets as tracked markets)
notes TextField Optional notes

Apple ASO Models

AppleApp

Represents an Apple application from App Store.

Field Type Description
id UUID Primary key
name CharField App name
bundle_id CharField Unique bundle identifier (e.g., com.example.app)

AppleAppCountryLanguage

Represents app localization for a specific country and language.

Field Type Description
id UUID Primary key
app ForeignKey Reference to AppleApp
country CharField ISO 2-letter country code
language CharField ISO language code

AppleAppKeyword

Keywords tracked for a specific Apple app localization.

Field Type Description
id UUID Primary key
acl ForeignKey Reference to AppleAppCountryLanguage
text CharField Keyword text

ASOAppleProject

Apple ASO project configuration for tracking app performance across multiple markets.

Field Type Description
id UUID Primary key
project OneToOneField Reference to base Project
app ForeignKey Reference to AppleApp
markets ManyToMany Country-language markets being tracked for this app
keywords ManyToMany Keywords to track across all markets
competitors ManyToMany Competitor app markets to monitor (in same markets as tracked markets)
notes TextField Optional notes

Access Control

The system implements a two-level access control system:

Workspace Level

Users can have one of three roles in a workspace:

  1. OWNER - Full control, automatic access to all projects
  2. ADMIN - Can manage workspace settings and users
  3. VIEWER - Read-only access to workspace

Project Level

Non-owner users need explicit project access:

  1. ADMIN - Full control over the project
  2. VIEWER - Read-only access to the project

Access Rules

  • Workspace owners automatically have access to all projects in their workspace
  • Other users must be workspace members first
  • Project access is granted through ProjectUserAccess entries
  • A user must be a workspace member before they can be granted project access

Usage Examples

Creating a Workspace

from workspaces.models import Workspace
from users.models import CustomUser

user = CustomUser.objects.get(email='[email protected]')
workspace = Workspace.objects.create(
    name='Marketing Agency',
    owner=user
)

Creating an Android ASO Project

from workspaces.models import (
    Project, ProjectType, AndroidApp,
    AndroidAppCountryLanguage, AndroidAppKeyword, ASOAndroidProject
)

# Create or get Android app
app = AndroidApp.objects.create(
    name='My App',
    package_id='com.example.myapp'
)

# Create localizations for markets you want to track
us_acl = AndroidAppCountryLanguage.objects.create(
    app=app,
    country='US',
    language='en'
)
de_acl = AndroidAppCountryLanguage.objects.create(
    app=app,
    country='DE',
    language='de'
)

# Create keywords for each market
us_keyword1 = AndroidAppKeyword.objects.create(
    acl=us_acl,
    text='messaging app'
)
us_keyword2 = AndroidAppKeyword.objects.create(
    acl=us_acl,
    text='secure messenger'
)

# Create project
project = Project.objects.create(
    name='My App ASO',
    workspace=workspace,
    type=ProjectType.ASO_ANDROID
)

# Add ASO configuration with M2M relationships
aso_config = ASOAndroidProject.objects.create(
    project=project,
    app=app
)

# Link markets and keywords to project
aso_config.markets.set([us_acl, de_acl])
aso_config.keywords.set([us_keyword1, us_keyword2])

Adding Users to Workspace

from workspaces.models import WorkspaceUser, WorkspaceRole

# Add user as admin
workspace_user = WorkspaceUser.objects.create(
    workspace=workspace,
    user=new_user,
    role=WorkspaceRole.ADMIN
)

Granting Project Access

from workspaces.models import ProjectUserAccess, ProjectRole

# Grant viewer access to project
ProjectUserAccess.objects.create(
    workspace_user=workspace_user,
    project=project,
    role=ProjectRole.VIEWER
)

Checking Access

# Check if user has access to project
if project.user_has_access(user):
    # User can access project
    pass

# Get all accessible projects in workspace
projects = workspace.get_projects_for_user(user)

Database Schema

All models use UUID primary keys and include timestamps (created_at, updated_at) through the BaseModel abstract class.

Relationships

  • WorkspaceProject: One-to-Many
  • WorkspaceWorkspaceUser: One-to-Many
  • ProjectASOAndroidProject: One-to-One
  • ProjectASOAppleProject: One-to-One
  • AndroidAppAndroidAppCountryLanguage: One-to-Many
  • AppleAppAppleAppCountryLanguage: One-to-Many
  • AndroidAppCountryLanguageAndroidAppKeyword: One-to-Many
  • AppleAppCountryLanguageAppleAppKeyword: One-to-Many

Migrations

The models are defined in two Django apps:

  • users - Contains CustomUser model
  • workspaces - Contains all workspace and project models

To apply migrations:

# Using Docker
docker compose run --rm web uv run python manage.py makemigrations
docker compose run --rm web uv run python manage.py migrate

# Local development
uv run python manage.py makemigrations
uv run python manage.py migrate