feat: Ipad app production readiness, Colony orchestration, Social posting (#44)
All checks were successful
Production Readiness / backend-contracts (push) Successful in 1m47s
Production Readiness / webos-typecheck (push) Successful in 1m50s
Production Readiness / ipad-parse (push) Successful in 1m34s

#38 Ipad app production readiness, Colony orchestration, Social posting

Co-authored-by: Sayan Datta <sayan@Sayans-MacBook-Air.local>
Reviewed-on: #44
This commit was merged in pull request #44.
This commit is contained in:
2026-05-03 18:30:38 +05:30
parent 59d398abc3
commit eeb684b46c
86 changed files with 20349 additions and 1655 deletions

View File

@@ -15,11 +15,8 @@ final class VelocitySmokeTests: XCTestCase {
[
"Dashboard",
"Clients",
"Imports",
"Communications",
"Calendar",
"Oracle",
"Sentinel",
"Inventory",
"Settings",
]
@@ -32,17 +29,22 @@ final class VelocitySmokeTests: XCTestCase {
[
"Dashboard",
"Clients",
"Imports",
"Communications",
"Calendar",
"Oracle",
"Operator Posture",
"Inventory",
"Settings",
]
)
}
func testShowroomDockExcludesAdministrativeWorkspaces() {
let sectionNames = Set(AppSection.allCases.map(\.rawValue))
XCTAssertFalse(sectionNames.contains("Imports"))
XCTAssertFalse(sectionNames.contains("Sentinel"))
XCTAssertFalse(sectionNames.contains("Oracle"))
XCTAssertEqual(AppSection.communications.dockTitle, "Comms")
}
func testAppConfigParsesExplicitValuesAndRejectsPlaceholders() {
XCTAssertEqual(
AppConfig.parsedValue(from: ["BASE_URL": " https://velocity.desineuron.in/api "], key: "BASE_URL"),
@@ -182,7 +184,7 @@ final class VelocitySmokeTests: XCTestCase {
email: nil,
hasPassword: false,
hasBearerToken: true,
source: .buildConfiguration
source: .secureDeviceStorage
)
XCTAssertEqual(open.dreamWeaverAuthenticationDescription, "No gateway key configured")
}
@@ -913,6 +915,64 @@ final class VelocitySmokeTests: XCTestCase {
XCTAssertEqual(AppStoreRefreshPolicy.leadEventLimitPerLead, 4)
}
func testMobileEdgeBulkRefreshContractDecodesCalendarAlertsAndLeadEvents() throws {
let payload = Data(
"""
{
"calendar_events": [
{
"calendar_event_id": "cal-1",
"lead_id": "lead-1",
"title": "Site visit",
"description": "Walkthrough",
"start_at": "2026-04-26T07:00:00Z",
"end_at": "2026-04-26T08:00:00Z",
"all_day": false,
"status": "confirmed",
"reminder_minutes": [15],
"created_by": "user",
"location": "Sales lounge",
"created_at": "2026-04-26T06:30:00Z"
}
],
"lead_events": {
"lead-1": [
{
"event_id": "evt-1",
"lead_id": "lead-1",
"channel": "manual_note",
"direction": "inbound",
"provider": null,
"capture_mode": "operator_note",
"consent_state": "granted",
"timestamp": "2026-04-26T06:00:00Z",
"duration_seconds": null,
"summary": "Client wants a larger balcony.",
"raw_reference": null,
"recording_ref": null,
"provider_metadata": {},
"created_at": "2026-04-26T06:00:00Z"
}
]
},
"alerts": {
"pending_insights": 2,
"upcoming_calendar_events_24h": 1,
"pending_transcriptions": 3,
"generated_at": "2026-04-26T06:35:00Z"
},
"generated_at": "2026-04-26T06:35:00Z"
}
""".utf8
)
let bundle = try JSONDecoder().decode(VelocityMobileEdgeBulkDTO.self, from: payload)
XCTAssertEqual(bundle.calendarEvents.first?.calendarEventId, "cal-1")
XCTAssertEqual(bundle.leadEvents["lead-1"]?.first?.eventId, "evt-1")
XCTAssertEqual(bundle.alerts.pendingInsights, 2)
XCTAssertEqual(bundle.alerts.upcomingCalendarEvents24h, 1)
}
func testAppStoreRefreshPolicyPrioritizesHighestScoreLeads() {
let leads = [
VelocityLeadDTO(
@@ -970,4 +1030,280 @@ final class VelocitySmokeTests: XCTestCase {
["lead-2", "lead-3"]
)
}
func testCanonicalDashboardMetricsIgnoreLocalDriftAndMatchBackendContracts() {
let contacts = [
VelocityCanonicalContactListItemDTO(
personId: "person-1",
fullName: "Whale Buyer",
primaryPhone: nil,
buyerType: "investor",
leadId: "lead-1",
leadStatus: "qualified",
budgetBand: nil,
urgency: "high",
primaryInterest: nil,
intentScore: 0.95,
engagementScore: 0.70,
urgencyScore: 0.80,
interactionCount: 3,
pendingTasks: 1,
lastInteractionAt: nil,
createdAt: nil
),
VelocityCanonicalContactListItemDTO(
personId: "person-2",
fullName: "Standard Buyer",
primaryPhone: nil,
buyerType: "end_user",
leadId: "lead-2",
leadStatus: "new",
budgetBand: nil,
urgency: nil,
primaryInterest: nil,
intentScore: 0.40,
engagementScore: 0.30,
urgencyScore: 0.20,
interactionCount: 1,
pendingTasks: 0,
lastInteractionAt: nil,
createdAt: nil
),
]
let leads = VelocityLeadDTO.activeLeadSummaries(from: contacts)
let board = [
VelocityKanbanColumnDTO(status: "new", label: "New", count: 4, items: []),
VelocityKanbanColumnDTO(status: "qualified", label: "Qualified", count: 3, items: []),
]
let taskRefresh = AppStore.CalendarTaskRefresh(
tasks: [],
pendingTaskCount: 5,
pendingTaskIDs: ["task-1", "task-2", "task-3", "task-4", "task-5"],
urgentTaskCount: 2
)
let today = ISO8601DateFormatter().string(from: Date())
let metrics = AppStore.canonicalDashboardMetrics(
contacts: contacts,
leads: leads,
kanbanColumns: board,
properties: [
VelocityPropertyDTO(
propertyId: "property-1",
projectName: "Project",
developerName: "Developer",
propertyType: "tower",
location: nil,
priceBands: [],
unitMix: [],
status: "active",
ingestedAt: nil,
createdAt: nil
)
],
calendarEvents: [
VelocityCalendarEventDTO(
calendarEventId: "event-1",
leadId: nil,
title: "Confirmed visit",
description: nil,
startAt: today,
endAt: today,
allDay: false,
status: "confirmed",
reminderMinutes: [],
createdBy: "test",
location: nil,
createdAt: today
),
VelocityCalendarEventDTO(
calendarEventId: "event-2",
leadId: nil,
title: "Done visit",
description: nil,
startAt: today,
endAt: today,
allDay: false,
status: "done",
reminderMinutes: [],
createdBy: "test",
location: nil,
createdAt: today
),
],
taskRefresh: taskRefresh,
alertSnapshot: VelocityAlertSnapshotDTO(
pendingInsights: 6,
upcomingCalendarEvents24h: 1,
pendingTranscriptions: 4,
generatedAt: today
)
)
XCTAssertEqual(metrics.leadCount, 7)
XCTAssertEqual(metrics.whaleLeadCount, 1)
XCTAssertEqual(metrics.propertyCount, 1)
XCTAssertEqual(metrics.todayCalendarCount, 1)
XCTAssertEqual(metrics.pendingTaskCount, 5)
XCTAssertEqual(metrics.urgentTaskCount, 2)
XCTAssertEqual(metrics.pendingInsights, 6)
XCTAssertEqual(metrics.pendingTranscriptions, 4)
}
func testDreamWeaverHealthDecodesCheckpointReadinessAliases() throws {
let payload = Data(#"{"status":"ok","comfyui":true,"preferred_checkpoint_available":false}"#.utf8)
let health = try JSONDecoder().decode(HealthResponse.self, from: payload)
XCTAssertEqual(health.status, "ok")
XCTAssertEqual(health.comfyui, true)
XCTAssertEqual(health.checkpointReady, false)
}
func testCommunicationsThreadRequiresCanonicalCRMPersonLink() throws {
let linked = try JSONDecoder().decode(
VelocityCommsThreadDTO.self,
from: Data(#"{"threadId":"thread-1","provider":"waha","personId":"person-1","phoneE164":"+910000000000","displayName":"Amina","channel":"whatsapp","status":"open","unreadCount":1,"lastMessageAt":null,"updatedAt":"2026-04-29T10:00:00+00:00","lastMessagePreview":"Hi","crmPerson":{"id":"person-1","fullName":"Amina","primaryPhone":"+910000000000","primaryEmail":null,"buyerType":"investor","leadStatus":"new","projectName":"Tower"}}"#.utf8)
)
let unlinked = try JSONDecoder().decode(
VelocityCommsThreadDTO.self,
from: Data(#"{"threadId":"thread-2","provider":"mock","personId":null,"phoneE164":"+910000000001","displayName":null,"channel":"whatsapp","status":"open","unreadCount":0,"lastMessageAt":null,"updatedAt":"2026-04-29T10:00:00+00:00","lastMessagePreview":null,"crmPerson":null}"#.utf8)
)
XCTAssertTrue(linked.isLinkedToCanonicalPerson)
XCTAssertEqual(linked.displayTitle, "Amina")
XCTAssertFalse(unlinked.isLinkedToCanonicalPerson)
XCTAssertEqual(unlinked.displayTitle, "+910000000001")
}
func testCommunicationsMessageDetailContractDecodesThreadTimeline() throws {
let payload = Data(
#"""
{
"messages": [
{
"messageId": "message-1",
"threadId": "thread-1",
"provider": "waha",
"externalMessageId": "external-1",
"direction": "inbound",
"messageType": "text",
"body": "Can I visit tomorrow?",
"mediaUrl": null,
"mediaMimeType": null,
"deliveryStatus": "delivered",
"sentAt": "2026-04-29T10:00:00+00:00",
"deliveredAt": null,
"readAt": null,
"rawPayload": {"source": "webhook"},
"createdAt": "2026-04-29T10:00:01+00:00"
},
{
"messageId": "message-2",
"threadId": "thread-1",
"provider": "waha",
"externalMessageId": "external-2",
"direction": "outbound",
"messageType": "text",
"body": "Yes, I can schedule it.",
"mediaUrl": null,
"mediaMimeType": null,
"deliveryStatus": "sent",
"sentAt": "2026-04-29T10:02:00+00:00",
"deliveredAt": null,
"readAt": null,
"rawPayload": {},
"createdAt": "2026-04-29T10:02:00+00:00"
}
],
"thread": {
"threadId": "thread-1",
"provider": "waha",
"personId": "person-1",
"phoneE164": "+910000000000",
"displayName": "Amina",
"channel": "whatsapp",
"status": "open",
"unreadCount": 1,
"lastMessageAt": "2026-04-29T10:02:00+00:00",
"updatedAt": "2026-04-29T10:02:00+00:00",
"lastMessagePreview": "Yes, I can schedule it.",
"crmPerson": {
"id": "person-1",
"fullName": "Amina",
"primaryPhone": "+910000000000",
"primaryEmail": null,
"buyerType": "investor",
"leadStatus": "new",
"projectName": "Tower"
}
}
}
"""#.utf8
)
let detail = try JSONDecoder().decode(VelocityCommsThreadMessagesDTO.self, from: payload)
XCTAssertEqual(detail.messages.count, 2)
XCTAssertEqual(detail.messages.first?.direction, "inbound")
XCTAssertEqual(detail.messages.last?.deliveryStatus, "sent")
XCTAssertEqual(detail.thread.threadId, "thread-1")
XCTAssertTrue(detail.thread.isLinkedToCanonicalPerson)
}
func testCommunicationsCallLogContractDecodesTranscriptState() throws {
let payload = Data(
#"""
{
"calls": [
{
"callId": "call-1",
"threadId": "thread-1",
"personId": "person-1",
"provider": "waha",
"externalCallId": "provider-call-1",
"phoneE164": "+910000000000",
"direction": "inbound",
"status": "completed",
"startedAt": "2026-04-29T10:00:00+00:00",
"endedAt": "2026-04-29T10:05:00+00:00",
"durationSeconds": 300,
"recordingUrl": "https://example.test/recording.mp3",
"transcriptId": null,
"transcriptText": "Client asked for a Sunday visit.",
"rawPayload": {"provider": "waha"},
"createdAt": "2026-04-29T10:05:01+00:00"
}
],
"thread": {
"threadId": "thread-1",
"provider": "waha",
"personId": "person-1",
"phoneE164": "+910000000000",
"displayName": "Amina",
"channel": "whatsapp",
"status": "open",
"unreadCount": 0,
"lastMessageAt": "2026-04-29T10:02:00+00:00",
"updatedAt": "2026-04-29T10:02:00+00:00",
"lastMessagePreview": "Done",
"crmPerson": {
"id": "person-1",
"fullName": "Amina",
"primaryPhone": "+910000000000",
"primaryEmail": null,
"buyerType": "investor",
"leadStatus": "new",
"projectName": "Tower"
}
}
}
"""#.utf8
)
let detail = try JSONDecoder().decode(VelocityCommsThreadCallsDTO.self, from: payload)
XCTAssertEqual(detail.calls.count, 1)
XCTAssertEqual(detail.calls.first?.durationSeconds, 300)
XCTAssertEqual(detail.calls.first?.transcriptText, "Client asked for a Sunday visit.")
XCTAssertTrue(detail.thread.isLinkedToCanonicalPerson)
}
}