wiki/archiv/doc_system.html

477 lines
17 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PowerOn System Documentation</title>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #2c3e50;
border-bottom: 3px solid #3498db;
padding-bottom: 10px;
margin-bottom: 30px;
}
h2 {
color: #34495e;
border-bottom: 2px solid #ecf0f1;
padding-bottom: 8px;
margin-top: 40px;
margin-bottom: 20px;
}
h3 {
color: #2c3e50;
margin-top: 25px;
margin-bottom: 15px;
}
h4 {
color: #34495e;
margin-top: 20px;
margin-bottom: 10px;
}
.code-block {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 4px;
padding: 15px;
margin: 15px 0;
font-family: 'Courier New', monospace;
overflow-x: auto;
}
.code-inline {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 3px;
padding: 2px 6px;
font-family: 'Courier New', monospace;
font-size: 0.9em;
}
.warning {
background-color: #fff3cd;
border: 1px solid #ffeaa7;
border-radius: 4px;
padding: 15px;
margin: 15px 0;
border-left: 4px solid #f39c12;
}
.success {
background-color: #d4edda;
border: 1px solid #c3e6cb;
border-radius: 4px;
padding: 15px;
margin: 15px 0;
border-left: 4px solid #28a745;
}
.info {
background-color: #d1ecf1;
border: 1px solid #bee5eb;
border-radius: 4px;
padding: 15px;
margin: 15px 0;
border-left: 4px solid #17a2b8;
}
.table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.table th, .table td {
border: 1px solid #ddd;
padding: 12px;
text-align: left;
}
.table th {
background-color: #f8f9fa;
font-weight: 600;
}
.table tr:nth-child(even) {
background-color: #f8f9fa;
}
.nav-toc {
background-color: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 4px;
padding: 20px;
margin: 20px 0;
}
.nav-toc ul {
list-style-type: none;
padding-left: 0;
}
.nav-toc li {
margin: 8px 0;
}
.nav-toc a {
color: #3498db;
text-decoration: none;
}
.nav-toc a:hover {
text-decoration: underline;
}
.phase-status {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 0.8em;
font-weight: bold;
text-transform: uppercase;
}
.phase-completed {
background-color: #d4edda;
color: #155724;
}
.phase-in-progress {
background-color: #fff3cd;
color: #856404;
}
.phase-not-started {
background-color: #f8d7da;
color: #721c24;
}
</style>
</head>
<body>
<div class="container">
<h1>PowerOn System Documentation</h1>
<div class="nav-toc">
<h3>Table of Contents</h3>
<ul>
<li><a href="#timestamp-architecture">1. Timestamp & Datetime Architecture</a></li>
<li><a href="#system-overview">2. System Overview</a></li>
<li><a href="#development-guidelines">3. Development Guidelines</a></li>
<li><a href="#api-standards">4. API Standards</a></li>
<li><a href="#testing-standards">5. Testing Standards</a></li>
</ul>
</div>
<section id="timestamp-architecture">
<h2>1. Timestamp & Datetime Architecture</h2>
<div class="info">
<strong>Status:</strong> <span class="phase-status phase-completed">COMPLETED</span>
<strong>Last Updated:</strong> 2025-01-21
<strong>Scope:</strong> Entire codebase (Gateway + Frontend Agents)
</div>
<h3>1.1 Overview</h3>
<p>
PowerOn implements a unified timestamp architecture that ensures consistency across all modules,
APIs, and frontend components. The system uses <strong>float UTC timestamps</strong> as the single
source of truth for all temporal data, eliminating timezone confusion and format inconsistencies.
</p>
<h3>1.2 Core Design Principles</h3>
<h4>Single Source of Truth: UTC Timestamps</h4>
<ul>
<li><strong>ALL</strong> timestamp fields use <code class="code-inline">float</code> type representing UTC seconds since epoch</li>
<li><strong>NO</strong> mixed types (datetime, str, float) for the same field type</li>
<li><strong>NO</strong> ISO string timestamps in data models or API responses</li>
<li><strong>ONLY</strong> system-level fields (<code class="code-inline">_createdAt</code>, <code class="code-inline">_modifiedAt</code>) remain as ISO strings</li>
</ul>
<h4>Consistent Data Flow Architecture</h4>
<div class="code-block">
Database ←→ Models ←→ API Endpoints ←→ Frontend
↓ ↓ ↓ ↓
Float Float Float Float
UTC UTC UTC UTC
</div>
<h4>Frontend-Backend Contract</h4>
<ul>
<li><strong>Backend Sends:</strong> Float UTC timestamps (e.g., <code class="code-inline">1705852800.0</code>)</li>
<li><strong>Frontend Receives:</strong> Float UTC timestamps</li>
<li><strong>Frontend Displays:</strong> Local timezone converted from UTC</li>
<li><strong>Frontend Sends Back:</strong> Float UTC timestamps (if sending timestamps)</li>
</ul>
<h3>1.3 Technical Implementation Standards</h3>
<h4>Backend (Python) Standards</h4>
<div class="code-block">
# ✅ CORRECT - Use UTC timestamp functions
from modules.shared.timezoneUtils import get_utc_timestamp, create_expiration_timestamp
# For current time
current_time = get_utc_timestamp() # Returns float
# For expiration times
expires_at = create_expiration_timestamp(3600) # 1 hour from now
# For model fields
class UserConnection(BaseModel):
connectedAt: float = Field(default_factory=get_utc_timestamp)
expiresAt: Optional[float] = None
</div>
<h4>Frontend (JavaScript) Standards</h4>
<div class="code-block">
// ✅ CORRECT - Expect float UTC timestamps
import { isExpiredUtc, formatUtcForDisplay } from '../shared/timezoneUtils.js';
// Check expiration (expects float)
if (isExpiredUtc(connection.expiresAt)) {
// Handle expired token
}
// Display in local timezone (expects float)
const localTime = formatUtcForDisplay(connection.connectedAt);
</div>
<h4>API Response Standards</h4>
<div class="code-block">
// ✅ CORRECT - All timestamp fields as float
{
"id": "conn_123",
"connectedAt": 1705852800.0,
"expiresAt": 1705856400.0,
"lastChecked": 1705852800.0
}
// ❌ WRONG - Mixed types or ISO strings
{
"id": "conn_123",
"connectedAt": "2024-01-21T12:00:00Z", // ISO string
"expiresAt": 1705856400.0, // Float
"lastChecked": "2024-01-21T12:00:00Z" // ISO string
}
</div>
<h3>1.4 Database Schema Standards</h3>
<h4>Timestamp Field Types</h4>
<div class="code-block">
-- ✅ CORRECT - All timestamp fields as FLOAT/DOUBLE
CREATE TABLE connections (
id VARCHAR(255) PRIMARY KEY,
connectedAt DOUBLE NOT NULL, -- UTC timestamp in seconds
expiresAt DOUBLE, -- UTC timestamp in seconds
lastChecked DOUBLE NOT NULL -- UTC timestamp in seconds
);
-- ❌ WRONG - Mixed types
CREATE TABLE connections (
id VARCHAR(255) PRIMARY KEY,
connectedAt DATETIME, -- Datetime type
expiresAt DOUBLE, -- Float type
lastChecked VARCHAR(255) -- String type
);
</div>
<h4>System Fields (Keep as-is)</h4>
<div class="code-block">
-- ✅ CORRECT - System fields remain as strings
CREATE TABLE connections (
id VARCHAR(255) PRIMARY KEY,
connectedAt DOUBLE NOT NULL, -- User data: float UTC
_createdAt VARCHAR(255), -- System data: ISO string
_modifiedAt VARCHAR(255) -- System data: ISO string
);
</div>
<h3>1.5 Model Field Standards</h3>
<p>All timestamp fields in Pydantic models must follow these standards:</p>
<div class="code-block">
class UserConnection(BaseModel, ModelMixin):
"""Data model for a user's connection to an external service"""
id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Unique ID of the connection")
userId: str = Field(description="ID of the user this connection belongs to")
authority: AuthAuthority = Field(description="Authentication authority")
externalId: str = Field(description="User ID in the external system")
externalUsername: str = Field(description="Username in the external system")
externalEmail: Optional[EmailStr] = Field(None, description="Email in the external system")
status: ConnectionStatus = Field(default=ConnectionStatus.ACTIVE, description="Connection status")
connectedAt: float = Field(default_factory=get_utc_timestamp, description="When the connection was established (UTC timestamp in seconds)")
lastChecked: float = Field(default_factory=get_utc_timestamp, description="When the connection was last verified (UTC timestamp in seconds)")
expiresAt: Optional[float] = Field(None, description="When the connection expires (UTC timestamp in seconds)")
</div>
<div class="warning">
<strong>⚠️ Critical Rule:</strong> All timestamp fields MUST include "UTC timestamp in seconds" in their description
for consistency and documentation purposes.
</div>
<h3>1.6 Direct Float Storage</h3>
<p>The system now stores all timestamp fields directly as float values in the database:</p>
<div class="code-block">
def to_dict(self) -> Dict[str, Any]:
"""
Convert a Pydantic model to a dictionary.
Handles both Pydantic v1 and v2.
All timestamp fields remain as float values.
Returns:
Dict[str, Any]: Dictionary representation of the model
"""
# Get the raw dictionary
if hasattr(self, 'model_dump'):
data: Dict[str, Any] = self.model_dump() # Pydantic v2
else:
data: Dict[str, Any] = self.dict() # Pydantic v1
# All fields (including timestamps) remain in their original format
# No conversions needed - timestamps are already float
return data
</div>
<p><strong>Key Benefits:</strong></p>
<ul>
<li><strong>No unnecessary conversions</strong> between float and string</li>
<li><strong>Direct database storage</strong> as float values</li>
<li><strong>Consistent data types</strong> across the entire system</li>
<li><strong>Better performance</strong> without string parsing</li>
</ul>
<h3>1.7 Utility Functions</h3>
<h4>Backend Utilities (Python)</h4>
<div class="code-block">
from modules.shared.timezoneUtils import get_utc_timestamp, create_expiration_timestamp
# Get current UTC timestamp
current_time = get_utc_timestamp() # Returns float
# Create expiration timestamp (seconds from now)
expires_in_1_hour = create_expiration_timestamp(3600)
expires_in_1_day = create_expiration_timestamp(86400)
# Get UTC datetime object
utc_now = get_utc_now() # Returns datetime object in UTC
</div>
<h4>Frontend Utilities (JavaScript)</h4>
<div class="code-block">
import {
isExpiredUtc,
formatUtcForDisplay,
getExpiresInSeconds,
normalizeTimestamp
} from '../shared/timezoneUtils.js';
// Check if timestamp is expired
if (isExpiredUtc(connection.expiresAt)) {
console.log('Connection expired');
}
// Format for display (converts to local timezone)
const displayTime = formatUtcForDisplay(connection.connectedAt);
// Get seconds until expiration
const secondsLeft = getExpiresInSeconds(connection.expiresAt);
// Normalize any timestamp format to float (backward compatibility)
const normalized = normalizeTimestamp(connection.lastChecked);
</div>
<h3>1.8 Migration Rules</h3>
<p>When converting existing timestamp data to the new format:</p>
<div class="code-block">
def migrate_timestamp_field(value):
"""Migrate any timestamp format to float UTC timestamp"""
if isinstance(value, float):
return value # Already float, assume UTC
elif isinstance(value, str):
if value.endswith('Z') or 'T' in value:
# ISO string format
dt = datetime.fromisoformat(value.replace('Z', '+00:00'))
return dt.timestamp()
else:
# Try parsing as float
return float(value)
elif isinstance(value, datetime):
# Convert to UTC timestamp
return value.timestamp()
else:
raise ValueError(f"Cannot migrate timestamp: {value}")
</div>
<h3>1.9 Implementation Status</h3>
<table class="table">
<thead>
<tr>
<th>Component</th>
<th>Status</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<tr>
<td>Backend Models</td>
<td><span class="phase-status phase-completed">COMPLETED</span></td>
<td>11 models, 15 timestamp fields standardized as float</td>
</tr>
<tr>
<td>Backend APIs</td>
<td><span class="phase-status phase-completed">COMPLETED</span></td>
<td>All endpoints return float timestamps</td>
</tr>
<tr>
<td>Frontend Modules</td>
<td><span class="phase-status phase-completed">COMPLETED</span></td>
<td>All utilities expect float timestamps</td>
</tr>
<tr>
<td>Database Storage</td>
<td><span class="phase-status phase-completed">COMPLETED</span></td>
<td>All timestamps stored as float (no string conversion)</td>
</tr>
<tr>
<td>Testing & Validation</td>
<td><span class="phase-status phase-completed">COMPLETED</span></td>
<td>24 tests passing, all functionality verified</td>
</tr>
</tbody>
</table>
</section>
<section id="system-overview">
<h2>2. System Overview</h2>
<p>This section will contain the overall system architecture documentation.</p>
</section>
<section id="development-guidelines">
<h2>3. Development Guidelines</h2>
<p>This section will contain coding standards and best practices.</p>
</section>
<section id="api-standards">
<h2>4. API Standards</h2>
<p>This section will contain API design and response format standards.</p>
</section>
<section id="testing-standards">
<h2>5. Testing Standards</h2>
<p>This section will contain testing methodologies and standards.</p>
</section>
<footer style="margin-top: 50px; padding-top: 20px; border-top: 1px solid #eee; color: #666; text-align: center;">
<p>PowerOn System Documentation - Last Updated: 2025-01-21</p>
</footer>
</div>
</body>
</html>