Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions mindtrace/hardware/mindtrace/hardware/api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"""

import logging
from datetime import datetime
from datetime import datetime, UTC
from typing import Dict, Any

from fastapi import FastAPI, Request
Expand Down Expand Up @@ -94,7 +94,7 @@ async def camera_error_handler(request: Request, exc: CameraError):
message=str(exc),
error_type=type(exc).__name__,
error_code=error_code,
timestamp=datetime.utcnow()
timestamp=datetime.now(UTC)
).model_dump(mode="json")
)

Expand All @@ -111,7 +111,7 @@ async def value_error_handler(request: Request, exc: ValueError):
message=str(exc),
error_type="ValueError",
error_code="VALIDATION_ERROR",
timestamp=datetime.utcnow()
timestamp=datetime.now(UTC)
).model_dump(mode="json")
)

Expand All @@ -128,7 +128,7 @@ async def key_error_handler(request: Request, exc: KeyError):
message=f"Resource not found: {exc}",
error_type="KeyError",
error_code="RESOURCE_NOT_FOUND",
timestamp=datetime.utcnow()
timestamp=datetime.now(UTC)
).model_dump(mode="json")
)

Expand All @@ -145,7 +145,7 @@ async def general_exception_handler(request: Request, exc: Exception):
message="An unexpected error occurred",
error_type=type(exc).__name__,
error_code="INTERNAL_SERVER_ERROR",
timestamp=datetime.utcnow()
timestamp=datetime.now(UTC)
).model_dump(mode="json")
)

Expand All @@ -155,7 +155,7 @@ async def health_check() -> Dict[str, Any]:
"""Health check endpoint."""
return {
"status": "healthy",
"timestamp": datetime.utcnow().isoformat(),
"timestamp": datetime.now(UTC).isoformat(),
"version": "1.0.0",
"service": "Camera API"
}
Expand All @@ -177,11 +177,11 @@ async def root():
@app.middleware("http")
async def log_requests(request: Request, call_next):
"""Log all incoming requests."""
start_time = datetime.utcnow()
start_time = datetime.now(UTC)

response = await call_next(request)

process_time = (datetime.utcnow() - start_time).total_seconds()
process_time = (datetime.now(UTC) - start_time).total_seconds()

logger.info(
f"{request.method} {request.url} - "
Expand Down
4 changes: 2 additions & 2 deletions mindtrace/hardware/mindtrace/hardware/models/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
response formatting across all endpoints.
"""

from datetime import datetime
from datetime import datetime, UTC
from typing import Dict, List, Optional, Any, Tuple
from pydantic import BaseModel, Field

Expand All @@ -14,7 +14,7 @@ class BaseResponse(BaseModel):
"""Base response model for all API endpoints."""
success: bool
message: str
timestamp: datetime = Field(default_factory=datetime.utcnow)
timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC))


class BoolResponse(BaseResponse):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Database Seeding

This directory contains the database seeding functionality for MindTrace. The seed file creates the initial organization and superadmin user required for the system to function.

## What gets created

- **Organization**: `mindtrace` (Enterprise plan with unlimited users and projects)
- **Superadmin User**: `mindtracesuperadmin` with email `superadmin@mindtrace.com`
- **Role**: Super Admin with full system access

## Usage

### Option 1: Standalone Script (Recommended)

Run the standalone script from the poseidon directory:

```bash
cd mindtrace/ui/mindtrace/ui/poseidon
python seed_db.py
```

This will show an interactive menu with options:
1. **Safe seed** - Creates initial data without overwriting existing records
2. **Reset and seed** - ⚠️ **WARNING**: Deletes ALL data and creates fresh initial data
3. **Exit** - Quit the seeding tool

### Option 2: Direct Import

```python
import asyncio
from poseidon.backend.database.seed import seed_database, reset_and_seed

# Safe seed (won't overwrite existing data)
asyncio.run(seed_database())

# Reset and seed (deletes all data first)
asyncio.run(reset_and_seed())
```

### Option 3: Command Line Module

```bash
cd mindtrace/ui/mindtrace/ui/poseidon
python -m poseidon.backend.database.seed
```

## Important Notes

### Password Security
- The script generates a **secure random password** for the superadmin user
- **SAVE THE PASSWORD** shown in the output - it's only displayed once
- The password is hashed using SHA-256 before storage

### Safe Operations
- Running the seed multiple times is safe
- The script checks for existing data and won't create duplicates
- Only use the "reset and seed" option if you want to start fresh

### Generated Data Example
```
✓ Created organization 'mindtrace' (ID: 687a0a02729546165b913abf)
- Admin registration key: ORG_eZJRFioOpE8574tFgePKmAhJL3VgzsniNupryNxL1KU

✓ Created superadmin user 'mindtracesuperadmin' (ID: 687a0a02729546165b913ac0)
- Email: superadmin@mindtrace.com
- Default password: nFNfL7FckLsE1guyA6ZGEw # ⚠️ SAVE THIS PASSWORD!
- Role: OrgRole.SUPER_ADMIN
- Organization: mindtrace
```

## Database Schema

The seeding process creates data that follows the Link field structure:

- **Organization**: Standard organization with enterprise features
- **User**: Linked to the organization with `OrgRole.SUPER_ADMIN` role
- **Relationships**: Proper Link field connections between models

## Verification

The script includes automatic verification that:
- Organization was created successfully
- User was created successfully
- User is properly linked to organization
- User has correct super admin role
- All data is active and accessible

## Troubleshooting

If seeding fails:
1. Ensure database connection is available
2. Check that all models are properly defined
3. Verify the database initialization completes successfully
4. Check the error output for specific issues

For database connection issues, ensure your MongoDB instance is running and accessible via the configured connection string in your settings.
119 changes: 119 additions & 0 deletions mindtrace/ui/mindtrace/ui/poseidon/poseidon/backend/database/init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
from beanie import init_beanie
from motor.motor_asyncio import AsyncIOMotorClient
from typing import List, Type
import sys

from poseidon.backend.database.models.user import User
from poseidon.backend.database.models.organization import Organization
from poseidon.backend.database.models.project import Project
from poseidon.backend.database.models.image import Image
from poseidon.backend.database.models.camera import Camera
from poseidon.backend.database.models.model import Model
from poseidon.backend.database.models.model_deployment import ModelDeployment
from poseidon.backend.core.config import settings

# Global client and initialization state
_client = None
_is_initialized = False

def rebuild_all_models():
"""Rebuild all models in the correct order to resolve forward references."""
try:
# Get all modules that contain models
organization_module = sys.modules['poseidon.backend.database.models.organization']
project_module = sys.modules['poseidon.backend.database.models.project']
user_module = sys.modules['poseidon.backend.database.models.user']
camera_module = sys.modules['poseidon.backend.database.models.camera']
model_module = sys.modules['poseidon.backend.database.models.model']
model_deployment_module = sys.modules['poseidon.backend.database.models.model_deployment']

# Add all models to each module's global namespace for cross-references
models_dict = {
'Organization': Organization,
'Project': Project,
'User': User,
'Camera': Camera,
'Model': Model,
'ModelDeployment': ModelDeployment,
}

for module in [organization_module, project_module, user_module, camera_module, model_module, model_deployment_module]:
for name, model_class in models_dict.items():
setattr(module, name, model_class)

# Rebuild models in dependency order
# 1. Organization has no dependencies
Organization.model_rebuild()
print("✓ Organization model rebuilt")

# 2. Project and User have circular dependencies, so rebuild both
Project.model_rebuild()
print("✓ Project model rebuilt")

User.model_rebuild()
print("✓ User model rebuilt")

# 3. Other models depend on Organization, Project, and User
Camera.model_rebuild()
print("✓ Camera model rebuilt")

Model.model_rebuild()
print("✓ Model model rebuilt")

ModelDeployment.model_rebuild()
print("✓ ModelDeployment model rebuilt")

print("✓ All models rebuilt successfully")

except Exception as e:
print(f"❌ Error rebuilding models: {e}")
raise

async def initialize_database():
"""Initialize the database with all models registered to resolve ForwardRef links."""
global _client, _is_initialized

if _is_initialized:
# Always rebuild all models to ensure forward references are resolved
rebuild_all_models()
return _client

print("Initializing database...")

_client = AsyncIOMotorClient(settings.MONGO_URI)

# Register ALL models with Beanie at once to resolve ForwardRef links
document_models = [
Organization, # Put Organization first so it's defined before other models
Project, # Put Project before models that reference it
User, # Put User before models that reference it
Image,
Camera,
Model,
ModelDeployment,
]

# Let Beanie handle the model initialization and forward reference resolution
await init_beanie(
database=_client[settings.DB_NAME],
document_models=document_models
)

print("✓ Beanie initialized with all models")

# Rebuild all models to ensure forward references are resolved
rebuild_all_models()

_is_initialized = True
print("✓ Database initialization complete")
return _client

def get_database_client():
"""Get the database client (must call initialize_database first)."""
global _client
return _client

def is_database_initialized():
"""Check if database has been initialized."""
global _is_initialized
return _is_initialized
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .camera import Camera
from .model import Model
from .model_deployment import ModelDeployment
from .enums import SubscriptionPlan

__all__ = [
"User",
Expand All @@ -13,5 +14,6 @@
"Image",
"Camera",
"Model",
"ModelDeployment"
"ModelDeployment",
"SubscriptionPlan",
]
Loading