feat: Ipad app production readiness, Colony orchestration, Social posting
This commit is contained in:
@@ -36,6 +36,7 @@ from backend.auth.dependencies import get_current_user
|
||||
logger = logging.getLogger("velocity.admin_surface")
|
||||
|
||||
router = APIRouter()
|
||||
dashboard_router = APIRouter()
|
||||
|
||||
# ── RBAC guard ────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -61,6 +62,128 @@ def _pool(request: Request):
|
||||
return pool
|
||||
|
||||
|
||||
class OfflineReplayAuditRecord(BaseModel):
|
||||
id: str
|
||||
kind: str
|
||||
operation: str
|
||||
targetId: str | None = None
|
||||
queuedAt: str
|
||||
attemptCount: int
|
||||
lastAttemptAt: str | None = None
|
||||
lastError: str | None = None
|
||||
|
||||
|
||||
class OfflineReplayAuditRequest(BaseModel):
|
||||
records: list[OfflineReplayAuditRecord] = Field(default_factory=list)
|
||||
pendingCount: int
|
||||
|
||||
|
||||
@dashboard_router.get("/metrics", summary="Canonical dashboard metrics for WebOS and iPad parity")
|
||||
async def get_dashboard_metrics(
|
||||
request: Request,
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
pool = _pool(request)
|
||||
tenant_id = user.tenant_id or "tenant_velocity"
|
||||
async with pool.acquire() as conn:
|
||||
row = await conn.fetchrow(
|
||||
"""
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM crm_leads WHERE tenant_id = $1)::int AS lead_count,
|
||||
(
|
||||
SELECT COUNT(DISTINCT p.person_id)::int
|
||||
FROM crm_people p
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT current_value
|
||||
FROM intel_qd_scores q
|
||||
WHERE q.person_id = p.person_id
|
||||
ORDER BY q.computed_at DESC
|
||||
LIMIT 1
|
||||
) q ON TRUE
|
||||
WHERE p.tenant_id = $1
|
||||
AND (
|
||||
COALESCE(p.buyer_type, '') ILIKE '%whale%'
|
||||
OR COALESCE(q.current_value, 0) >= 0.90
|
||||
)
|
||||
) AS whale_lead_count,
|
||||
(SELECT COUNT(*) FROM inventory_properties WHERE tenant_id = $1 AND status <> 'archived')::int AS property_count,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM user_calendar_events
|
||||
WHERE tenant_id = $1
|
||||
AND owner_user_id = $2
|
||||
AND status NOT IN ('cancelled', 'done')
|
||||
AND start_at >= date_trunc('day', NOW())
|
||||
AND start_at < date_trunc('day', NOW()) + INTERVAL '1 day'
|
||||
)::int AS today_calendar_count,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM intel_reminders
|
||||
WHERE COALESCE(tenant_id, $1) = $1
|
||||
AND status IN ('pending', 'open', 'scheduled', 'snoozed', 'confirmed')
|
||||
)::int AS pending_task_count,
|
||||
(
|
||||
SELECT COUNT(*)
|
||||
FROM intel_reminders
|
||||
WHERE COALESCE(tenant_id, $1) = $1
|
||||
AND status IN ('pending', 'open', 'scheduled', 'snoozed', 'confirmed')
|
||||
AND priority IN ('urgent', 'high')
|
||||
)::int AS urgent_task_count,
|
||||
(SELECT COUNT(*) FROM insight_recommendations WHERE tenant_id = $1 AND status = 'pending')::int AS pending_insights,
|
||||
(SELECT COUNT(*) FROM edge_transcription_jobs WHERE tenant_id = $1 AND status = 'pending')::int AS pending_transcriptions
|
||||
""",
|
||||
tenant_id,
|
||||
user.user_id,
|
||||
)
|
||||
return {
|
||||
"status": "ok",
|
||||
"data": {
|
||||
"leadCount": row["lead_count"],
|
||||
"whaleLeadCount": row["whale_lead_count"],
|
||||
"propertyCount": row["property_count"],
|
||||
"todayCalendarCount": row["today_calendar_count"],
|
||||
"pendingTaskCount": row["pending_task_count"],
|
||||
"urgentTaskCount": row["urgent_task_count"],
|
||||
"pendingInsights": row["pending_insights"],
|
||||
"pendingTranscriptions": row["pending_transcriptions"],
|
||||
},
|
||||
"meta": {"generatedAt": datetime.now(timezone.utc).isoformat()},
|
||||
}
|
||||
|
||||
|
||||
@dashboard_router.post("/offline-replay/audit", summary="Publish native offline replay queue observability")
|
||||
async def publish_offline_replay_audit(
|
||||
body: OfflineReplayAuditRequest,
|
||||
request: Request,
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
pool = _pool(request)
|
||||
async with pool.acquire() as conn:
|
||||
await conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS mobile_offline_replay_audits (
|
||||
audit_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id TEXT NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
pending_count INT NOT NULL,
|
||||
records JSONB NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)
|
||||
"""
|
||||
)
|
||||
await conn.execute(
|
||||
"""
|
||||
INSERT INTO mobile_offline_replay_audits (tenant_id, user_id, pending_count, records)
|
||||
VALUES ($1, $2, $3, $4::jsonb)
|
||||
""",
|
||||
user.tenant_id,
|
||||
user.user_id,
|
||||
body.pendingCount,
|
||||
json.dumps([record.model_dump() for record in body.records]),
|
||||
)
|
||||
return {"status": "ok", "pendingCount": body.pendingCount}
|
||||
|
||||
|
||||
# ── Pydantic Models ───────────────────────────────────────────────────────────
|
||||
|
||||
VALID_ACTION_TYPES = {
|
||||
|
||||
Reference in New Issue
Block a user