11 KiB
Import Map Analysis: interfaces ↔ connectors ↔ security
Overview
This document maps all imports between modules/interfaces, modules/connectors, and modules/security to identify structural issues, circular dependencies, and architectural concerns.
Architectural Principle:
- ✅ Connectors (infrastructure) can import from Security (infrastructure)
- ✅ Interfaces (business logic) can import from Security (infrastructure)
- ✅ Interfaces (business logic) can import from Connectors (infrastructure)
- ❌ Connectors should NOT import from Interfaces (business logic)
Import Dependencies Map
CONNECTORS → SECURITY
connectorDbPostgre.py
- Imports from security:
from modules.security.rbac import RbacClass(line 13)- Usage:
- Runtime instantiation:
RbacClass(self)ingetRecordsetWithRBAC()(line 1073) - Creates
RbacClassinstance to get user permissions
- Runtime instantiation:
- Status: ✅ ARCHITECTURALLY CORRECT - Connectors can import from security module
SECURITY → CONNECTORS
security/rbac.py (moved from interfaces/interfaceRbac.py)
- Imports from connectors:
from modules.connectors.connectorDbPostgre import DatabaseConnector(line 11, inside TYPE_CHECKING)- Usage: Type hint only (
db: "DatabaseConnector") - Status: ✅ Fixed with TYPE_CHECKING to avoid circular import
- Architecture: ✅ Correct - Security module can import from connectors (infrastructure layer)
INTERFACES → CONNECTORS
interfaceBootstrap.py
- Imports from connectors:
from modules.connectors.connectorDbPostgre import DatabaseConnector(line 9)- Usage: Function parameter types (
initBootstrap(db: DatabaseConnector))
interfaceDbAppObjects.py
- Imports from connectors:
from modules.connectors.connectorDbPostgre import DatabaseConnector(line 12)- Usage: Class initialization (
self.db: DatabaseConnector)
- Imports from security:
from modules.security.rbac import RbacClass(line 17)- Usage: RBAC permission checking
- Architecture: ✅ Correct - Interfaces can import from security (infrastructure layer)
interfaceDbChatObjects.py
- Imports from connectors:
from modules.connectors.connectorDbPostgre import DatabaseConnector(line 29)- Usage: Class initialization
interfaceDbComponentObjects.py
- Imports from connectors:
from modules.connectors.connectorDbPostgre import DatabaseConnector(line 13)- Usage: Class initialization
interfaceVoiceObjects.py
- Imports from connectors:
from modules.connectors.connectorVoiceGoogle import ConnectorGoogleSpeech(line 10)- Usage: Class initialization
Circular Dependency Analysis
CIRCULAR DEPENDENCY #1: RESOLVED ✅
connectorDbPostgre.py (line 13)
└─> imports RbacClass from security.rbac
└─> Uses: RbacClass(self) at runtime (line 1073)
security/rbac.py (line 11, inside TYPE_CHECKING)
└─> imports DatabaseConnector (type hint only)
Status: ✅ RESOLVED by moving RBAC to security module + TYPE_CHECKING
Architectural Fix:
- Moved
interfaceRbac.py→security/rbac.py - Connectors can import from security (infrastructure layer)
- Interfaces can import from security (business logic layer)
- No architectural violation: security is shared infrastructure
Solution Applied:
# security/rbac.py
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from modules.connectors.connectorDbPostgre import DatabaseConnector
class RbacClass:
def __init__(self, db: "DatabaseConnector"): # String annotation
self.db = db # Uses db at runtime, but import is deferred
Why This Works:
- At import time:
connectorDbPostgreimportsRbacClass✅ RbacClasstries to importDatabaseConnectorbut it's insideTYPE_CHECKING, so no actual import occurs ✅- At runtime: When
getRecordsetWithRBAC()callsRbacClass(self),DatabaseConnectoris already fully loaded ✅ - Runtime circular reference is safe because Python objects can reference each other once loaded
Architecture Analysis
Current Structure
┌─────────────────────────────────────────────────────────────┐
│ CONNECTORS │
│ (Database, External Services) │
│ │
│ connectorDbPostgre.py │
│ └─> Uses: RbacClass (runtime instantiation) ⚠️ │
│ │
│ connectorVoiceGoogle.py │
│ connectorTicketsClickup.py │
│ connectorTicketsJira.py │
└─────────────────────────────────────────────────────────────┘
▲
│ imports
│
┌─────────────────────────────────────────────────────────────┐
│ INTERFACES │
│ (Business Logic, Data Access Layer) │
│ │
│ security/rbac.py (moved from interfaces) │
│ └─> Uses: DatabaseConnector (type hint only) ✅ │
│ └─> Can be imported by both connectors and interfaces │
│ │
│ interfaceBootstrap.py │
│ └─> Uses: DatabaseConnector │
│ │
│ interfaceDbAppObjects.py │
│ └─> Uses: DatabaseConnector │
│ └─> Uses: security.rbac.RbacClass │
│ └─> Uses: interfaceBootstrap.initBootstrap │
│ │
│ interfaceDbChatObjects.py │
│ └─> Uses: DatabaseConnector │
│ │
│ interfaceDbComponentObjects.py │
│ └─> Uses: DatabaseConnector │
│ │
│ interfaceVoiceObjects.py │
│ └─> Uses: connectorVoiceGoogle.ConnectorGoogleSpeech │
└─────────────────────────────────────────────────────────────┘
Potential Issues & Recommendations
✅ RESOLVED ISSUES
- Circular Import: security.rbac ↔ connectorDbPostgre
- Status: ✅ Resolved by moving to security module + TYPE_CHECKING
- Impact: None - Proper architectural layering maintained
⚠️ POTENTIAL ISSUES
-
Tight Coupling: Interfaces depend on specific connectors
- Issue:
interfaceDbAppObjects.pydirectly importsDatabaseConnector - Impact: Makes it harder to swap database implementations
- Recommendation: Consider dependency injection or abstract base class
- Issue:
-
Connector importing from Security (connectorDbPostgre → security.rbac) ✅
- Status: ✅ RESOLVED - Moved RBAC to security module
- Current Usage: Runtime instantiation in
getRecordsetWithRBAC()(line 1073) - Code:
RbacInstance = RbacClass(self) permissions = RbacInstance.getUserPermissions(...) - Architecture: ✅ Correct - Connectors can import from security (infrastructure layer)
- Rationale: Security is shared infrastructure, not business logic
-
Multiple interfaces importing same connector
- Files importing DatabaseConnector:
interfaceBootstrap.pyinterfaceDbAppObjects.pyinterfaceDbChatObjects.pyinterfaceDbComponentObjects.py
- Impact: Medium - creates coupling
- Recommendation: Consider a shared database interface abstraction
- Files importing DatabaseConnector:
Recommendations
1. Move RBAC Logic Out of Connector
Current: connectorDbPostgre.getRecordsetWithRBAC() instantiates RbacClass(self) at runtime
Recommendation:
Move✅ RESOLVED - RBAC moved to security modulegetRecordsetWithRBAC()tointerfaceRbac.pyorinterfaceDbAppObjects.py- Connector should only handle raw database operations
- Interface layer handles RBAC filtering
2. Use Dependency Injection
Current: Interfaces directly import DatabaseConnector
Recommendation:
- Create abstract base class
DatabaseConnectorBase - Interfaces depend on abstraction, not concrete implementation
- Allows easier testing and swapping implementations
3. Consider Layered Architecture
┌─────────────────────────────────────┐
│ Interfaces (Business Logic) │
│ - Uses connectors via abstraction │
└─────────────────────────────────────┘
▲
│
┌─────────────────────────────────────┐
│ Connectors (Infrastructure) │
│ - No knowledge of interfaces │
└─────────────────────────────────────┘
4. Use TYPE_CHECKING for All Type-Only Imports
Current: security/rbac.py uses TYPE_CHECKING (moved from interfaces)
Recommendation: Use TYPE_CHECKING for all type-only imports between layers
Summary
Current State:
- ✅ 1 circular dependency RESOLVED (moved to security module)
- ✅ Architectural violation FIXED (RBAC moved to security)
- ⚠️ Multiple tight couplings to
DatabaseConnector(acceptable for now)
Architectural Health:
- Overall: 🟢 Good - Proper layering maintained
- Architecture: ✅ Connectors → Security (infrastructure) ✅ Interfaces → Security (infrastructure)
- Risk Level: Low - Clean separation of concerns
Completed Actions:
- ✅ DONE: Fixed circular import with TYPE_CHECKING
- ✅ DONE: Moved RBAC to security module (proper architectural layering)
- 🔄 OPTIONAL: Introduce abstraction layer for database connector (future improvement)